关于 secure-checkout
secure-checkout 面向构建或审计支付结账流程的开发者和店铺运营者,提供平台相关的安全指导,涵盖 TLS、CSP、支付令牌化及第三方脚本管理。
主要功能
- 01按平台提供结账安全指导
- 02TLS 与 HTTPS 配置
- 03CSP 与安全响应头实践
- 04支付令牌化指导
- 05第三方脚本审查
适用场景
- 01发现 XSS 后审计结账页面
- 02检查可接触支付表单的脚本
- 03准备 PCI 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 漏洞就可能引发类似 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 控制第三方脚本的放置位置 |
| 自定义 / 无头 | 由你的基础设施负责 | 由你的应用负责 — 实施包含随机数的逐请求 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 (redirect) — 将客户重定向到 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_DEBUG在wp-config.php中必须为false) - 没有自定义代码记录订单数据或支付详情
步骤 5 — 通过主机或插件配置 SSL 安全标头:
- 如果使用 Nginx 主机(Kinsta、WP Engine、Nexcess),请联系主机提供商添加 HSTS 和 X-Frame-Options 标头——这些标头通常已在托管式 WordPress 主机上预先配置
- 或者,安装 HTTP Headers(免费插件),无需编辑服务器配置,即可通过 WordPress 添加安全标头
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,检查当前使用的支付网关;确保没有使用会向服务器“直接提交”数据的网关
管理员账户安全:
- 前往 Account Settings → Users
- 检查所有用户账户,移除离职员工和承包商的账户
- 确保所有活动账户都已在各自的账户安全设置中启用 2FA
- 前往 Settings → Advanced Settings → API Accounts,检查 OAuth 凭据;撤销所有未使用的 API 令牌
自定义 / 无头架构
对于自定义店面,所有结账安全控制措施都需要自行实施。最关键的三项是:支付令牌化(确保服务器永远不会接触银行卡号)、在支付页面设置严格的 CSP(防止 Magecart 注入),以及使用带有安全标头的 HTTPS。
使用 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 设置内容安全策略(防止 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 脚本添加子资源完整性(SRI)——即使 CDN 遭到入侵,SRI 也能确保脚本内容未被篡改;使用
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 无法正常工作 | 将 https://js.stripe.com 和 https://hooks.stripe.com 添加到 frame-src;查看 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