secure-checkout について
secure-checkout は、決済フローを構築・監査する開発者や店舗運営者向けのスキルです。ホスト型・カスタム型ストアフロントについて、TLS、CSP、決済トークン化、サードパーティスクリプトの対策を案内します。
主な機能
- 01プラットフォーム別のチェックアウトセキュリティ
- 02TLS と HTTPS の設定
- 03CSP とセキュリティヘッダーの実践
- 04決済トークン化の案内
- 05サードパーティスクリプトの確認
活用シーン
- 01XSS 発見後のチェックアウトページ監査
- 02決済フォームに触れるスクリプトの確認
- 03PCI DSS 評価の準備
- 04カスタムチェックアウト移行時の保護
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ finsilabs/ awesome-ecommerce-skills --skill secure-checkoutインストール後、Claude Code で/secure-checkoutを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
tile.jsonevals/payment-tokenization-and-input-validatio/criteria.jsontask.mdevals/security-headers-and-csp-configuration/criteria.jsontask.mdevals/third-party-script-isolation-and-csp-vio/criteria.jsontask.md詳細
セキュアなチェックアウト
概要
決済ページは、攻撃者にとって最も価値の高い標的です。XSS の脆弱性が1つあるだけで、何千ものカード番号を盗む Magecart 型のカードスキミング攻撃につながる可能性があります。チェックアウトを保護するには、あらゆる場所で TLS を強制し、スクリプトの挿入を防ぐ厳格なコンテンツセキュリティポリシー(CSP)を実装し、決済のトークン化を使用して PCI の適用範囲を最小限に抑え、決済ページから必須ではないサードパーティスクリプトを削除する必要があります。幸いなことに、Shopify と BigCommerce は、こうしたインフラの大部分を自動的に処理します。WooCommerce のマーチャントは、ホスティングを設定し、セキュリティプラグインをインストールする必要があります。カスタムストアフロントでは、これらすべての対策を最初から実装する必要があります。
このスキルを使用する場面
- 決済情報を受け付けるチェックアウトフローを構築または監査する場合
- ペネトレーションテストやセキュリティスキャンで、決済ページの XSS、CSP、またはヘッダーの脆弱性が見つかった場合
- 決済フォームのコンテキストにアクセスできるページでの、サードパーティスクリプトの読み込みを確認する場合
- PCI DSS SAQ A-EP または SAQ D のコンプライアンス評価に備える場合
- ホスト型決済ページからカスタム UI に移行する場合(PCI の適用範囲が広がります)
基本的な指示
ステップ 1:プラットフォームごとのチェックアウトセキュリティに関する責任を把握する
| プラットフォーム | HTTPS / TLS | CSP ヘッダー | 決済のトークン化 | サードパーティスクリプトの制御 |
|---|---|---|---|---|
| Shopify | 自動 — Shopify が SSL 証明書を発行して更新します | Shopify がチェックアウトの CSP を管理します。テーマのページは確認が必要です | Shopify Payments とすべてのゲートウェイ連携でトークン化を使用します | Shopify の Script Manager と Customer Events を使用して、チェックアウト時に読み込まれるものを制御します |
| WooCommerce | ホスティングの責任です — Let's Encrypt またはホスティングプロバイダーから SSL をインストールします | サーバーの責任です — ホスティングまたはプラグインで設定します | 選択したゲートウェイによって決まります(Stripe Elements = SAQ A-EP) | WordPress のプラグインとテーマのスクリプトは全体で読み込まれます。条件付き読み込みを使用して、チェックアウト時には除外します |
| BigCommerce | 自動 — BigCommerce が SSL を発行し、HTTPS を強制します | BigCommerce がホスト型チェックアウトの CSP を管理します | BigCommerce のチェックアウトを通じて、選択した決済ゲートウェイが処理します | BigCommerce の Script Manager でサードパーティスクリプトの配置を制御します |
| カスタム / ヘッドレス | インフラの責任です | アプリケーションの責任です — リクエストごとに nonce を使用する CSP を実装します | Stripe Elements または Braintree Drop-in UI で実装します | 完全な制御権と責任があります — 明示的に実装する必要があります |
ステップ 2:プラットフォームごとのチェックアウトセキュリティ設定
Shopify
Shopify のホスト型チェックアウトは、利用可能なものの中でも特に安全です。Shopify 独自のドメイン(checkout.shopify.com または SSL 対応のカスタムドメイン)上で動作し、Shopify Payments のトークン化を使用しており、Shopify の CDN と WAF によって保護されています。
HTTPS の適用:
- Shopify は、すべてのストアとカスタムドメインに無料の SSL 証明書を自動的に発行します
- Online Store → Domains に移動し、カスタムドメインで SSL が有効になっていることを確認します
- Online Store → Preferences → Checkout and accounts で Redirect all traffic to HTTPS を有効にします
チェックアウト上のサードパーティ製スクリプト: Shopify のチェックアウト拡張モデル(Checkout Extensibility)では、チェックアウトページで実行できる処理が制限されています。これは PCI 準拠のための設計です。
- Settings → Customer events に移動し、トラッキングピクセルとスクリプトを管理します
- Customer Events 経由で追加されたスクリプトはサンドボックス化されたコンテキストで実行され、支払いデータにアクセスできません
- テーマコードや ScriptTag API を使ってチェックアウトページに JavaScript を挿入しないでください。これは SAQ A 準拠のために禁止されており、Shopify によってブロックされる場合があります
テーマのセキュリティレビュー:
- Online Store → Themes → Edit code に移動します
- テーマ内で、カート/チェックアウトページにおける
document.cookie、localStorage、fetchの参照を検索します。意図的に追加したものでない場合、これらは危険信号です - インストール済みアプリを確認します。Settings → Apps and sales channels に移動し、使用しなくなったアプリを削除します。インストール済みのアプリはそれぞれ、ストアフロントにスクリプトを挿入できます
管理者アカウントのセキュリティ(攻撃対象領域を縮小):
- Settings → Users and permissions に移動します
- すべてのスタッフアカウントで 2FA を必須にします。管理者アカウントの侵害は、攻撃者がチェックアウトの挙動を変更する最も一般的な手段です
- スタッフのアクセス権を、それぞれの役割に必要な権限のみに制限します
WooCommerce
WooCommerce のチェックアウトのセキュリティは、ほぼすべてホスティングの設定と決済ゲートウェイに依存します。TLS はホスティングプロバイダーが担当し、選択するゲートウェイによって、カード情報がサーバーに届くかどうかが決まります。
ステップ 1 — ストアで HTTPS を強制します:
- WordPress のホスティングコントロールパネル(cPanel、Kinsta、WP Engine)で、Let's Encrypt またはホスト組み込みの証明書を使って無料の SSL を有効にします
- Really Simple SSL(無料プラグイン)をインストールします。サイト全体で HTTPS を強制し、内部リンクを更新して、混在コンテンツの警告を一度に解消します
- 有効化後、Settings → SSL でリダイレクトが有効になっており、混在コンテンツの警告が表示されないことを確認します
ステップ 2 — カード情報をサーバーに保存しない決済ゲートウェイを選びます:
- Stripe(WooCommerce Stripe Payment Gateway) — Stripe Elements を使用します。Stripe の iframe に入力されたカード情報がサーバーに届くことはありません(SAQ A-EP)
- Stripe Checkout(リダイレクト) — 顧客を Stripe のホスト型ページにリダイレクトします。さらに簡単です(SAQ A)
- PayPal Standard — PayPal にリダイレクトします。SAQ A
- サーバーでカード番号を生データとして受信する必要があるゲートウェイは避けてください
ステップ 3 — セキュリティプラグインをインストールします:
- Wordfence Security(無料)をインストールします。Wordfence → Firewall に移動し、保護レベルを「Extended Protection」に設定します。これにより、WordPress アプリケーション層に WAF ルールが追加されます
- WP Activity Log(年間約 99 ドル)または Simple History(無料)をインストールします。注文の編集、プラグインのインストール、設定変更など、すべての管理者操作を記録します
- Settings → Discussion に移動し、有効になっている場合はチェックアウト/カートページのコメントを無効にします(XSS 攻撃対象領域を縮小できます)
ステップ 4 — チェックアウトページからスクリプトを削除します: WooCommerce は、デフォルトですべての有効なプラグインをすべてのページで読み込みます。チェックアウトページで不要なスクリプトが読み込まれないように、Asset CleanUp Pro(一度限り 25 ドル)を使用するか、条件付き PHP を追加します:
WooCommerce → Settings → Advanced に移動して、以下を確認します:
- デバッグログが無効であること(本番環境では
wp-config.phpのWP_DEBUGをfalseにする必要があります) - 注文データや決済情報を記録するカスタムコードがないこと
ステップ 5 — ホスティングまたはプラグインで SSL セキュリティヘッダーを設定します:
- Nginx ホスティング(Kinsta、WP Engine、Nexcess)を使用している場合は、HSTS ヘッダーと X-Frame-Options ヘッダーを追加するようホストに依頼します。これらは、マネージド WordPress ホストであらかじめ設定されていることが一般的です
- あるいは、サーバー設定を編集せずに WordPress 経由でセキュリティヘッダーを追加できる HTTP Headers(無料プラグイン)をインストールします
BigCommerce
BigCommerce のホスト型チェックアウトは PCI-DSS Level 1 認定を取得しており、対応ゲートウェイを使用すると、TLS、CSP、決済トークン化を自動的に処理します。
HTTPS の強制:
- BigCommerce はすべてのストアに対して SSL を自動的にプロビジョニングし、更新します
- Store Setup → Store Settings → Security に移動し、Force secure checkout が有効になっていることを確認します
- Storefront → SSL Certificate に移動し、カスタムドメインで SSL が有効になっていることを確認します
サードパーティスクリプトの制御:
- Storefront → Script Manager に移動します
- インストール済みのすべてのスクリプトを確認し、各スクリプトの Placement 設定を確認します
- チェックアウトで実行する必要のないスクリプト(分析、広告、チャット)は、Placement を設定してチェックアウトページを除外します
- Script Manager のスクリプトはストアフロントのコンテキストで実行されます。BigCommerce のチェックアウト自体は、別のより制限の厳しい CSP で保護されています
チェックアウトの決済セキュリティ:
- BigCommerce Payments と認定済み決済ゲートウェイ(Stripe、Braintree、PayPal)はトークン化を使用するため、カードデータが BigCommerce やお使いのアプリケーションサーバーに渡ることはありません
- Store Setup → Payments に移動して、有効なゲートウェイを確認します。サーバーへの「direct post」を使用するゲートウェイを使っていないことを確認してください
管理者アカウントのセキュリティ:
- Account Settings → Users に移動します
- すべてのユーザーアカウントを確認し、退職した従業員や契約業者のアカウントを削除します
- すべての有効なアカウントで、個別のアカウントセキュリティ設定から 2FA enabled になっていることを確認します
- Settings → Advanced Settings → API Accounts に移動し、OAuth 認証情報を確認します。使用していない API トークンはすべて取り消してください
Custom / Headless
カスタムストアフロントでは、すべてのチェックアウトセキュリティ制御を実装する必要があります。特に重要なのは、決済のトークン化(サーバーがカード番号を扱わないようにするため)、決済ページでの厳格な CSP(Magecart のインジェクションを防ぐため)、およびセキュリティヘッダーを付与した HTTPS の 3 つです。
Stripe Elements による決済トークン化(SAQ A-EP):
// Client-side: Stripe handles card data in an iframe — your code never sees card numbers
const stripe = await loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);
const elements = stripe.elements({ clientSecret });
const paymentElement = elements.create('payment');
paymentElement.mount('#payment-element');
// On submit: Stripe handles card capture; your server receives only a paymentIntentId
const { error, paymentIntent } = await stripe.confirmPayment({
elements,
confirmParams: { return_url: `${window.location.origin}/order-confirmation` },
});
// Your server confirms via paymentIntentId — never a card number
HTTPS とセキュリティヘッダー(Next.js の例):
// next.config.ts
export default {
async headers() {
return [
{
source: '/(.*)',
headers: [
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
{ key: 'X-Frame-Options', value: 'DENY' },
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), payment=()' },
],
},
{
// No caching on checkout; no indexing by search engines
source: '/checkout(.*)',
headers: [
{ key: 'Cache-Control', value: 'no-store, no-cache, must-revalidate' },
{ key: 'X-Robots-Tag', value: 'noindex' },
],
},
];
},
};
リクエストごとの nonce を使用する Content Security Policy(Magecart を防止):
// middleware.ts — generate a new nonce per request; static nonces can be bypassed
export function middleware(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const csp = [
`default-src 'self'`,
`script-src 'self' 'nonce-${nonce}' https://js.stripe.com`,
`style-src 'self' 'nonce-${nonce}'`,
`frame-src https://js.stripe.com https://hooks.stripe.com`,
`connect-src 'self' https://api.stripe.com`,
`img-src 'self' data: https:`,
`object-src 'none'`,
`base-uri 'self'`,
`form-action 'self'`,
`upgrade-insecure-requests`,
`report-uri /api/csp-report`,
].join('; ');
const response = NextResponse.next();
response.headers.set('Content-Security-Policy', csp);
response.headers.set('x-nonce', nonce); // Pass to layout for script nonce attributes
return response;
}
CSP 違反の監視:
// app/api/csp-report/route.ts — log violations; alert on checkout page violations
export async function POST(req: NextRequest) {
const body = await req.json();
const violation = body['csp-report'];
await logger.warn('CSP Violation', {
documentUri: violation['document-uri'],
violatedDirective: violation['violated-directive'],
blockedUri: violation['blocked-uri'],
});
// A CSP violation on a payment page may indicate an active Magecart attack
if (violation['document-uri']?.includes('/checkout')) {
await alertSecurityTeam('CSP violation on checkout page', violation);
}
return new NextResponse(null, { status: 204 });
}
Zod によるサーバーサイド入力検証:
import { z } from 'zod';
const checkoutSchema = z.object({
email: z.string().email().max(255),
name: z.string().min(1).max(200).regex(/^[\p{L}\p{M}\s\-'.]+$/u),
address: z.string().min(1).max(500),
city: z.string().min(1).max(100),
postalCode: z.string().min(1).max(20),
country: z.string().length(2), // ISO 3166-1 alpha-2
});
export async function POST(req: NextRequest) {
const body = await req.json();
const result = checkoutSchema.safeParse(body);
if (!result.success) {
return NextResponse.json({ errors: result.error.flatten() }, { status: 400 });
}
// Proceed with validated data only
}
ベストプラクティス
- チェックアウトを独立したセキュリティゾーンとして扱う — 最も制限の厳しい CSP を適用し、必須ではないサードパーティスクリプトをすべて無効にします。また、決済ページでの CSP 違反はすべて、Magecart インシデントの可能性があるものとして扱います
- 決済ページに JavaScript をインラインで記述しない — nonce ベースの CSP と外部スクリプトを使用します。
script-srcに'unsafe-inline'を追加すると、CSP の目的が完全に損なわれます - 必須ではないアプリとプラグインを削除する — インストール済みの Shopify アプリ、WordPress プラグイン、BigCommerce スクリプトは、いずれも潜在的な攻撃対象領域です。ストアで実際に使用していないものはすべて削除してください
- CDN スクリプトに Subresource Integrity(SRI)を追加する — SRI によって、CDN が侵害された場合でもスクリプトの内容が改ざんされていないことを確認できます。
openssl dgst -sha256 -binary script.js | openssl base64で生成します - エッジで WAF 保護を有効にする — Cloudflare WAF(無料プラン)またはホスティングプロバイダーの WAF により、OWASP Top 10 攻撃がアプリケーションに到達する前にブロックされます
- CI で依存関係の脆弱性をスキャンする —
npm auditを実行し、Snyk または Dependabot を使用します。チェックアウトのバンドルに含まれる npm パッケージが侵害されることは、Magecart のインジェクションと同じくらい危険です
よくある問題
| 問題 | 解決策 |
|---|---|
| CSP によって Stripe Elements の iframe が機能しない | frame-src に https://js.stripe.com と https://hooks.stripe.com を追加します。最新の完全な許可リストについては、Stripe の CSP ドキュメントを確認してください |
スタイルを適用するために 'unsafe-inline' を追加している | 代わりにインラインスタイルには nonce を使用します。'unsafe-inline' を指定すると、そのディレクティブの CSP 保護が完全に無効になります |
| TLS 証明書の有効期限が切れている | 自動更新機能付きの Let's Encrypt(Certbot)または CDN のマネージド証明書を使用します。Shopify と BigCommerce は自動更新されます。WooCommerce/カスタムストアのみ手動更新が必要です |
| チェックアウトページで分析スクリプトが読み込まれる | 分析の初期化処理に条件チェックを追加し、/checkout ルートでは読み込みをスキップします。Shopify では Customer Events の配置設定を使用します |
| 決済フィールドにアクセスできるサードパーティ製チャットウィジェット | チェックアウトページからチャットウィジェットを完全に削除します。正当なサポート用途であっても、決済フォームの値を読み取る必要はありません |
関連スキル
- @fraud-detection
- @account-security
- @bot-protection
- @pci-dss-compliance
- @gdpr-ecommerce