payment-pci-security について
VTEX の決済コネクターやヘッドレス決済フローを構築する開発者向けのスキルで、PCI DSS と Secure Proxy の利用を扱います。カードデータを非 PCI 環境に持ち込まず、必要な認可を Secure Proxy 経由にし、機密情報の保存や記録を避ける方法を説明します。
主な機能
- 01Secure Proxy の要否を判断
- 02認可と認可後の処理を分離
- 03BFF によるカード情報転送の防止
- 04カード情報の永続保存を禁止
- 05機密カード情報のログ出力を防止
活用シーン
- 01クレジットカード決済コネクターの構築
- 02カード情報の保存とログの監査
- 03ヘッドレスストアの決済フロー設計
- 04認可と返金などの後続処理の分離
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ vtex/ skills --skill payment-pci-securityインストール後、Claude Code で/payment-pci-securityを入力して読み込まれたか確認します。
詳細
PCI コンプライアンスとセキュアプロキシ
このスキルを使用する場面
次の場合にこのスキルを使用してください。
- クレジットカード、デビットカード、または提携カードを受け付ける決済コネクターを構築する場合
- コネクターでカードデータを処理する必要がある場合、またはアクワイアラーと通信する必要がある場合
- ホスティング環境でセキュアプロキシが必要かどうかを判断する場合
- PCI DSS 準拠についてコネクターを監査する場合(データの保存、ログ記録、送信)
次の場合にはこのスキルを使用しないでください。
- PPP エンドポイントの契約とレスポンス形式 —
payment-provider-protocolを使用してください - 冪等性と重複防止 —
payment-idempotencyを使用してください - 非同期決済フロー(Boleto、Pix)とコールバック —
payment-async-flowを使用してください - POS/VTEX Sales App の対面カード決済(Gateway の
cardフィールドが null の場合)—payment-ppp-posを使用してください
判断ルール
- コネクターが非 PCI 環境(すべての VTEX IO アプリを含む)でホストされている場合、セキュアプロキシを必ず使用してください。
- コネクターが PCI DSS 認証(QSA が署名した AOC)を取得している場合は、生のカードデータを使用してアクワイアラーに直接接続できます。
- Create Payment リクエストに
secureProxyUrlがあるか確認してください。存在する場合、セキュアプロキシが有効であり、必ず使用してください。 secureProxyUrlは Create Payment(オーソリ)リクエストにのみ含まれます。 キャンセル、キャプチャ、売上確定、返金の操作ではカードデータを送信せず、このフィールドも受け取りません。オーソリ後の呼び出しは、認証情報とoutbound-accessポリシーを使用して PSP API に直接送信します。これらの操作ではカードデータを扱わないため、PCI コンプライアンスへの影響はありません。- カードトークン(
numberToken、holderToken、cscToken)が有効なのは、secureProxyUrl経由で送信された場合のみです。プロキシはアクワイアラーに転送する前に、これらを実際のデータに置き換えます。 - 保存が許可されるのは、
card.bin(先頭 6 桁)、card.numberLength、card.expirationのみです。それ以外はすべて禁止されています。 - 開発環境であっても、カードデータをログ、データベース、ファイル、キャッシュ、エラートラッカー、APM ツールに含めてはいけません。
厳守事項
制約:非 PCI 環境では secureProxyUrl を必ず使用する
コネクターが非 PCI 環境(すべての VTEX IO アプリを含む)でホストされている場合、アクワイアラーとの通信には Create Payment リクエストの secureProxyUrl を必ず使用してください。生のカードデータを使用してアクワイアラーに直接接続してはいけません。リクエストに secureProxyUrl フィールドがある場合、セキュアプロキシが有効であり、必ず使用してください。
これが重要な理由 非 PCI 環境では、生のカードデータを扱うことが許可されていません。アクワイアラーに直接接続すると、Gateway の安全なデータ処理を回避することになり、PCI DSS に違反します。データ侵害、多額の罰金(月額 10 万ドル以上)、カード処理能力の喪失、法的責任につながる可能性があります。
検出
リクエストに secureProxyUrl があるにもかかわらず、コネクターが secureProxyUrl を経由せずにアクワイアラーのエンドポイントを直接呼び出している場合は、直ちに停止してください。アクワイアラーとの通信はすべてセキュアプロキシ経由で行う必要があります。
正しい例
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
const { paymentId, secureProxyUrl, card } = req.body;
if (secureProxyUrl) {
// Non-PCI: Route through Secure Proxy
const acquirerResponse = await fetch(secureProxyUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-PROVIDER-Forward-To": "https://api.acquirer.com/v2/payments",
"X-PROVIDER-Forward-MerchantId": process.env.ACQUIRER_MERCHANT_ID!,
"X-PROVIDER-Forward-MerchantKey": process.env.ACQUIRER_MERCHANT_KEY!,
},
body: JSON.stringify({
orderId: paymentId,
payment: {
cardNumber: card.numberToken, // Token, not real number
holder: card.holderToken, // Token, not real name
securityCode: card.cscToken, // Token, not real CVV
expirationMonth: card.expiration.month,
expirationYear: card.expiration.year,
},
}),
});
const result = await acquirerResponse.json();
// Build and return PPP response...
}
}
誤った例
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
const { paymentId, secureProxyUrl, card } = req.body;
// WRONG: Calling acquirer directly, bypassing Secure Proxy
// This connector is non-PCI but handles card data as if it were PCI-certified
const acquirerResponse = await fetch("https://api.acquirer.com/v2/payments", {
method: "POST",
headers: {
"Content-Type": "application/json",
MerchantId: process.env.ACQUIRER_MERCHANT_ID!,
},
body: JSON.stringify({
orderId: paymentId,
payment: {
// These are tokens but sent directly to acquirer — acquirer can't read tokens!
// And if raw data were here, this would be a PCI violation
cardNumber: card.numberToken,
holder: card.holderToken,
securityCode: card.cscToken,
},
}),
});
// This request will fail: acquirer receives tokens instead of real card data
// And the Secure Proxy was completely bypassed
}
セキュアプロキシの適用範囲はカードのオーソリのみです。オーソリ後の操作には適用されません
secureProxyUrl フィールドが含まれるのは、Create Payment リクエスト(カードのオーソリ)のみです。キャンセル、キャプチャ(売上確定)、返金のリクエストにはカードデータが含まれないため、secureProxyUrl は含まれません。これらのリクエストでは、tid、authorizationId、または paymentId を使ってトランザクションを参照します。
オーソリ後の呼び出しは、manifest.json の outbound-access ポリシーで認可された API 認証情報を持つ ExternalClient を使用して、PSP API に直接送信する必要があります。
これが重要な理由
キャンセル、キャプチャ、返金をセキュアプロキシ経由でルーティングしようとすると、これらのリクエストでは secureProxyUrl が undefined であるため失敗します。アーキテクチャ上、PCI に関する懸念はありません。機密性の高いカードデータを含むのはオーソリのみです。すべての PSP 通信をセキュアプロキシ経由にする必要があると思い込むエージェントや開発者は、undefined のプロキシ URL のデバッグに多くの時間を費やすことになります。
検出方法
キャンセル、キャプチャ、返金のハンドラーが secureProxyUrl を参照する、SecureExternalClient を使用する、またはセキュアプロキシ経由でのルーティングを試みる場合は、処理を中止してください。オーソリ後の操作には、直接 API 呼び出しを行う ExternalClient を使用してください。
正しい例 — 2 クライアント構成
// Authorization (Create Payment) — via Secure Proxy
import { SecureExternalClient } from "@vtex/payment-provider";
export class PspSecureClient extends SecureExternalClient {
public async authorize(data: object, secureProxyUrl: string) {
return this.http.post("/payments", data, {
secureProxy: secureProxyUrl,
} as any);
}
}
// Cancel, Capture, Refund — direct API calls
import { ExternalClient } from "@vtex/api";
export class PspClient extends ExternalClient {
public async capture(tid: string, amount: number) {
return this.http.post(
`/payments/${tid}/capture`,
{ amount },
{
headers: { "X-API-Key": "..." },
},
);
}
}
誤った例
// WRONG — trying to use SecureExternalClient for all operations
async settle(request: SettlementRequest) {
// secureProxyUrl does not exist on SettlementRequest — this is undefined
await this.secureClient.capture(request.tid, request.value, request.secureProxyUrl)
}
制約:ヘッドレスストアフロントの BFF は、カードデータを vtexpayments.com.br にプロキシしてはなりません
ヘッドレスストアフロントでは、Send payments information 呼び出し(POST https://{account}.vtexpayments.com.br/api/pub/transactions/{tid}/payments)は、購入者のブラウザーまたはネイティブアプリから発行する必要があります。マーチャントの BFF(Node、Next.js のルートハンドラー、エッジ関数、Lambda、リバースプロキシ、その他のサーバーサイドコンポーネント)は、ブラウザーからカード情報を受け取ってはならず、リダクションを行う場合でも、サーバー側に appKey/appToken がある場合でも、転送されるのが「トークン化」されたフィールドだけに見える場合でも、Payment Gateway に転送してはなりません。
この制約は、Secure Proxy の基盤となる PCI の原則を拡張したものです。PCI に準拠していない環境では、カードデータを扱うことは許可されません。決済コネクターの場合、その環境は IO アプリです。ヘッドレスストアフロントの場合は、マーチャントの BFF です。宛先は異なります。Secure Proxy はコネクターからアクワイアラーへの経路を保護し、ブラウザーから vtexpayments.com.br へのパターンはストアフロントから Payment Gateway への経路を保護します。しかし、ルールは同じです。生のカードデータは、認定された範囲内にとどめてください。
重要な理由
ヘッドレスストアフロントを運営するマーチャントが PCI DSS レベル 1 認定を取得していることは、ほとんどありません。カード番号、カード名義人の氏名、CVV をマーチャントの BFF 経由でルーティングすると、BFF と、BFF が接続するすべてのシステム(アプリケーションログ、APM、リバースプロキシ、ロードバランサー、エラートラッカー)が PCI の適用範囲に含まれます。カードデータを扱う PCI 非準拠環境の運用は、PCI DSS 要件 3 および 4 に違反し、カードネットワークから月額 5,000 ドルから 100,000 ドル超の罰金、必須のフォレンジック調査費用、カード決済処理能力の喪失、集団訴訟リスク、一部の管轄区域での刑事責任につながる可能性があります。
VTEX Payment Gateway(vtexpayments.com.br)は PCI DSS レベル 1 認定を取得しています。ブラウザーから Payment Gateway への経路を使えば、カードデータは認定された範囲内にとどまり、マーチャントの BFF はカードデータのフローから完全に除外されます。Send payments information エンドポイントは、前の Place Order ステップで設定された購入者のセッション Cookie によって認証されます。この通信にマーチャントの認証情報は必要ありません。
検出方法
BFF/サーバーサイドのコード(server/、bff/、api/、ルートハンドラー、ミドルウェア、エッジ関数、Lambda)に次のいずれかが見つかった場合は、直ちに作業を中止してください。
- BFF から
https://*.vtexpayments.com.br/api/pub/transactions/.../paymentsへのリクエスト - ブラウザーから
cardNumber、holderName、validationCode、csc、dueDate、または決済のfields一式を受け取るハンドラー - Send payments information エンドポイント用に、サーバー上で
vtexpayments.com.brを参照する「Payments client」/ExternalClient/axiosインスタンス
BFF が公開すべきエンドポイントは /api/bff/order/place(transactionId、orderGroup、merchantName を返す)と /api/bff/order/process(カードデータを使わずに /api/checkout/pub/gatewayCallback/{orderGroup} を呼び出す)です。カード情報を vtexpayments.com.br に転送するエンドポイントは決して公開してはなりません。
正しい例
async function sendPaymentDataDirect(args: {
account: string;
transactionId: string;
orderGroup: string;
merchantName: string;
paymentInformation: PaymentField[];
}): Promise<void> {
const {
account,
transactionId,
orderGroup,
merchantName,
paymentInformation,
} = args;
const response = await fetch(
`https://${account}.vtexpayments.com.br/api/pub/transactions/${transactionId}/payments?orderId=${orderGroup}`,
{
method: "POST",
credentials: "include",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(
paymentInformation.map((p) => ({
...p,
transaction: { id: transactionId, merchantName },
})),
),
},
);
if (!response.ok) {
throw new Error(`Payment submission failed: ${response.status}`);
}
}
誤った例
const VTEX_APP_KEY = process.env.VTEX_APP_KEY!;
const VTEX_APP_TOKEN = process.env.VTEX_APP_TOKEN!;
paymentRoutes.post("/", async (req: Request, res: Response) => {
const { transactionId, orderGroup, paymentInformation } = req.body as {
transactionId: string;
orderGroup: string;
paymentInformation: Array<{
paymentSystem: number;
installments: number;
value: number;
fields: {
cardNumber: string;
holderName: string;
validationCode: string;
dueDate: string;
};
}>;
};
const url = `https://${process.env.VTEX_ACCOUNT}.vtexpayments.com.br/api/pub/transactions/${transactionId}/payments?orderId=${orderGroup}`;
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-VTEX-API-AppKey": VTEX_APP_KEY,
"X-VTEX-API-AppToken": VTEX_APP_TOKEN,
},
body: JSON.stringify(paymentInformation),
});
res.json({ status: response.status });
});
制約:生のカードデータを保存してはなりません
コネクターは、完全なカード番号(PAN)、CVV/CSC、カード名義人の氏名、またはカードトークンの値を、データベース、ファイルシステム、キャッシュ、セッションストア、その他の永続的な媒体など、いかなる永続ストレージにも保存してはなりません。カードデータが存在してよいのは、リクエストのライフサイクル中のメモリ内に限られます。
重要な理由 生のカードデータの保存は PCI DSS 要件 3 に違反します。データ侵害が発生すると、顧客が不正利用の被害に遭うおそれがあります。その結果、カードネットワークから月額 5,000~100,000 ドルの罰金、必須のフォレンジック調査費用(50,000 ドル以上)、カード決済処理能力の喪失、集団訴訟、一部の管轄区域での刑事責任につながる可能性があります。
検出方法
コードがカード番号、CVV、カード名義人の氏名、またはトークンの値をデータベース、ファイル、キャッシュ(Redis、VBase)、その他の永続ストレージに書き込んでいる場合は、直ちに作業を中止してください。保存できるのは card.bin(先頭 6 桁)と card.numberLength のみです。
正しい例
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
const { paymentId, card, secureProxyUrl } = req.body;
// Only store non-sensitive card metadata
await paymentStore.save(paymentId, {
paymentId,
cardBin: card.bin, // First 6 digits — safe to store
cardNumberLength: card.numberLength, // Length — safe to store
cardExpMonth: card.expiration.month, // Expiration — safe to store
cardExpYear: card.expiration.year,
// DO NOT store: card.numberToken, card.holderToken, card.cscToken
});
// Use card tokens only in-memory for the Secure Proxy call
const acquirerResult = await callAcquirerViaProxy(secureProxyUrl, card);
// Return response — card data is now out of scope
res.status(200).json(buildResponse(paymentId, acquirerResult));
}
誤った例
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
const { paymentId, card } = req.body;
// CRITICAL PCI VIOLATION: Storing full card data in database
await database.query(
`INSERT INTO payments (payment_id, card_number, cvv, holder_name)
VALUES ($1, $2, $3, $4)`,
[paymentId, card.number, card.csc, card.holder],
);
// This single line can result in:
// - $100K/month fines from card networks
// - Mandatory forensic audit ($50K+)
// - Loss of card processing ability
// - Criminal liability
}
制約:機密性の高いカードデータをログに記録してはなりません
コネクターは、カード番号、CVV/CSC 値、カード名義人名、トークン値を、コンソール、ファイル、監視サービス、エラートラッカー、APM ツールなど、いかなるロギングシステムにも記録してはなりません。デバッグモードでも、開発環境でも同様です。
重要な理由 ログは通常、平文で保存され、長期間保持され、多くのチームメンバーがアクセスできます。ログ内のカードデータは PCI DSS 違反であり、データ侵害につながります。ログ集約サービス(Datadog、Splunk、CloudWatch)は複数のリージョンにデータを保存することがあり、侵害の影響範囲が拡大する可能性があります。
検出
コードに console.log、console.error、logger.info、logger.debug、または card.number、card.csc、card.holder、card.numberToken、card.holderToken、card.cscToken を含むロギング呼び出し、あるいはマスキングされていないリクエストボディ全体を含むロギング呼び出しがある場合は、直ちに作業を停止してください。ログに記録する前に、すべての機密フィールドをマスキングするか、記録対象から除外してください。
正しい例
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
const { paymentId, card, paymentMethod, value } = req.body;
// Safe logging — only non-sensitive fields
console.log("Processing payment", {
paymentId,
paymentMethod,
value,
cardBin: card?.bin, // First 6 digits only — safe
cardNumberLength: card?.numberLength, // Safe
});
// NEVER log the full request body for payment requests
// It contains card tokens or raw card data
}
function redactSensitiveFields(
body: Record<string, unknown>,
): Record<string, unknown> {
const redacted = { ...body };
if (redacted.card && typeof redacted.card === "object") {
const card = redacted.card as Record<string, unknown>;
redacted.card = {
bin: card.bin,
numberLength: card.numberLength,
expiration: card.expiration,
// All other fields redacted
};
}
return redacted;
}
誤った例
async function createPaymentHandler(
req: Request,
res: Response,
): Promise<void> {
// CRITICAL PCI VIOLATION: Logging the entire request body
// This includes card number, CVV, holder name, and/or token values
console.log("Payment request received:", JSON.stringify(req.body));
// ALSO WRONG: Logging specific card fields
console.log("Card number:", req.body.card.number);
console.log("CVV:", req.body.card.csc);
console.log("Card holder:", req.body.card.holder);
// ALSO WRONG: Logging tokens (they reference real card data)
console.log("Card token:", req.body.card.numberToken);
}
推奨パターン
Secure Proxy のデータフロー:
1. Gateway → POST /payments (with secureProxyUrl + tokenized card data) → Connector
2. Connector → POST secureProxyUrl (tokens in body, X-PROVIDER-Forward-To: acquirer URL) → Gateway
3. Gateway replaces tokens with real card data → POST acquirer URL → Acquirer
4. Acquirer → response → Gateway → Connector
5. Connector → Create Payment response → Gateway
オーソリ後のデータフロー(Secure Proxy なし):
1. Gateway → POST /payments/{id}/settlements → Connector
2. Connector → POST acquirer API directly (tid + amount, no card data) → Acquirer
3. Acquirer → response → Connector
4. Connector → Settlement response → Gateway
Secure Proxy モードを検出する:
interface CreatePaymentRequest {
paymentId: string;
value: number;
currency: string;
paymentMethod: string;
card?: {
holder?: string; // Raw (PCI) or absent (Secure Proxy)
holderToken?: string; // Token (Secure Proxy only)
number?: string; // Raw (PCI) or absent (Secure Proxy)
numberToken?: string; // Token (Secure Proxy only)
bin: string; // Always present — first 6 digits
numberLength: number; // Always present
csc?: string; // Raw (PCI) or absent (Secure Proxy)
cscToken?: string; // Token (Secure Proxy only)
expiration: { month: string; year: string };
};
secureProxyUrl?: string; // Present when Secure Proxy is active
secureProxyTokensURL?: string; // For custom token operations
callbackUrl: string;
miniCart: Record<string, unknown>;
}
function isSecureProxyActive(req: CreatePaymentRequest): boolean {
return !!req.secureProxyUrl;
}
トークンまたは生の値を使ってアクワイアラー向けリクエストを作成する:
function buildAcquirerRequest(paymentReq: CreatePaymentRequest) {
const card = paymentReq.card!;
return {
merchantOrderId: paymentReq.paymentId,
payment: {
// Use tokens if Secure Proxy, raw values if PCI-certified
cardNumber: card.numberToken ?? card.number!,
holder: card.holderToken ?? card.holder!,
securityCode: card.cscToken ?? card.csc!,
expirationDate: `${card.expiration.month}/${card.expiration.year}`,
amount: paymentReq.value,
},
};
}
適切なヘッダーを設定して Secure Proxy 経由でアクワイアラーを呼び出す:
async function callAcquirerViaProxy(
secureProxyUrl: string,
acquirerRequest: object,
): Promise<AcquirerResponse> {
const response = await fetch(secureProxyUrl, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
// X-PROVIDER-Forward-To tells the proxy where to send the request
"X-PROVIDER-Forward-To": process.env.ACQUIRER_API_URL!,
// Custom headers for the acquirer — prefix is stripped by the proxy
"X-PROVIDER-Forward-MerchantId": process.env.ACQUIRER_MERCHANT_ID!,
"X-PROVIDER-Forward-MerchantKey": process.env.ACQUIRER_MERCHANT_KEY!,
},
body: JSON.stringify(acquirerRequest),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(
`Secure Proxy call failed: ${response.status} ${errorText}`,
);
}
return response.json() as Promise<AcquirerResponse>;
}
// For PCI-certified environments, call acquirer directly
async function callAcquirerDirect(
acquirerRequest: object,
): Promise<AcquirerResponse> {
const response = await fetch(process.env.ACQUIRER_API_URL!, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
MerchantId: process.env.ACQUIRER_MERCHANT_ID!,
MerchantKey: process.env.ACQUIRER_MERCHANT_KEY!,
},
body: JSON.stringify(acquirerRequest),
});
return response.json() as Promise<AcquirerResponse>;
}
安全なロギングユーティリティ:
function safePaymentLog(label: string, body: Record<string, unknown>): void {
const safe = {
paymentId: body.paymentId,
paymentMethod: body.paymentMethod,
value: body.value,
currency: body.currency,
orderId: body.orderId,
hasCard: !!body.card,
hasSecureProxy: !!body.secureProxyUrl,
cardBin: (body.card as Record<string, unknown>)?.bin,
// Everything else is intentionally omitted
};
console.log(label, JSON.stringify(safe));
}
よくある失敗パターン
- PCI 非準拠環境でカードを直接扱う — Secure Proxy を使わずにアクワイアラー API を直接呼び出すことです。アクワイアラーは実際のカード番号ではなく、トークン(例:
#vtex#token#d799bae#number#)を受け取り、取引を拒否します。生データを利用できる場合でも、PCI 非準拠環境から送信することは PCI DSS 違反です。 - キャンセル/キャプチャ/返金に Secure Proxy を使う — これらの操作では
secureProxyUrlは受け取らず、カードデータも含まれません。Secure Proxy 経由で送ろうとすると、URL がundefinedであるため失敗します。オーソリ後の操作には、ExternalClientを使用して API を直接呼び出してください。 - 完全なカード番号(PAN)を保存する — 「参照」や「照合」のために、完全なカード番号をデータベースに保存することです。このデータが一度侵害されるだけで、月額 10 万ドルの罰金、義務付けられたフォレンジック監査、カード処理能力の永久的な喪失につながる可能性があります。
- デバッグのためにカード情報をログに記録する — 支払いの問題を調査するために
console.log(req.body)やconsole.log(card)を追加し、削除し忘れることです。カードデータはログファイル、監視ダッシュボード、ログ集約サービスに残ります。これは開発環境でも PCI 違反です。 - X-PROVIDER-Forward ヘッダーを削除する —
X-PROVIDER-Forward-Toヘッダーを設定せずに Secure Proxy へリクエストを送信することです。プロキシはリクエストの転送先が分からず、エラーを返します。 - トークン値を保存する —
card.numberToken、card.holderToken、card.cscTokenはトークンだから「安全」だと考えて、データベースやキャッシュに書き込むことです。トークンは実際のカードデータを参照するため、永続化してはなりません。
レビューチェックリスト
- Create Payment リクエストに
secureProxyUrlがある場合、コネクターはそれを使用していますか? -
SecureExternalClientは Create Payment(オーソリ)のみに使用され、キャンセル/キャプチャ/返金には使用されていませんか? - オーソリ後の操作(キャンセル、キャプチャ、返金)では、
ExternalClientを使って API を直接呼び出していますか? - Secure Proxy を呼び出す際、
X-PROVIDER-Forward-Toにアクワイアラーの API URL を設定していますか? - プロキシ経由で送信する場合、アクワイアラー固有のヘッダーに
X-PROVIDER-Forward-を付けていますか? - データベースに保存されるのは
card.bin、card.numberLength、card.expirationのみですか? - カード番号、CVV、カード名義人名、トークン値は、すべてのログ出力から除外されていますか?
- 支払いリクエストデータを安全にログ出力するためのマスキングユーティリティがありますか?
- コネクターは Secure Proxy(非 PCI)モードと直接接続(PCI 認定)モードの両方をサポートしていますか?
- エラーレスポンスをログに記録する際、アクワイアラー向けリクエストボディ(トークンを含む)は記録されていませんか?
関連スキル
payment-provider-framework— PPF の IO 配線、2 クライアントパターン(SecureExternalClient+ExternalClient)、およびoutbound-accessポリシーpayment-provider-protocol— エンドポイントの契約とレスポンス形式payment-idempotency—paymentId/requestIdの冪等性とステートマシンpayment-async-flow— 非同期決済方法、コールバック、7 日間の再試行期間payment-ppp-pos— POS のカード対面決済。Gateway のcardは null で、Secure Proxy は適用されません
参考資料
- Secure Proxy — フロー図、リクエスト/レスポンスの例、カスタムトークン、サポートされている JsonLogic 演算子を含む、Secure Proxy の完全なドキュメント
- PCI DSS コンプライアンス — PCI 認証要件、AOC 提出プロセス、Secure Proxy が必須となる条件
- 決済プロバイダーの実装 — Secure Proxy URL とトークン化されたカードフィールドを含む、Create Payment リクエスト本文などのエンドポイント実装ガイド
- Payment Provider Protocol(ヘルプセンター) — PCI の前提条件と Secure Proxy の要件を含む、プロトコルの概要
- Payment Provider Framework — 決済コネクター向けの VTEX IO フレームワーク(すべての IO アプリで Secure Proxy が必須)
- PCI Security Standards Council — PCI DSS の公式要件とコンプライアンス関連ドキュメント