移动应用能否通过 direct post 使用 SAQ A-EP?
明确结论
Direct Post 确实可能适用 SAQ A-EP,并非必须使用 iframe。这里所说的 Direct Post,通常是一种电子商务架构:支付表单由商户网站生成,消费者的浏览器将卡数据直接提交给符合 PCI DSS 要求的支付服务商。
对于使用原生控件收集卡信息的移动应用,不能只因这些控件“不会被第三方 JavaScript 修改”,就认定其符合 SAQ A-EP。原生应用与 SAQ A-EP 资格描述中的典型场景并不完全一致,例如“将支付页面交付到消费者浏览器”。能否使用该问卷,需要由收单机构或支付品牌结合实际数据流、应用架构和适用的 PCI DSS 版本确认。
如果原生应用自行创建卡号、有效期和 CVV 输入控件,再通过 API 直接提交给 PSP,通常不应自行将其归入 SAQ A-EP。获得明确确认前,应按更大的 PCI DSS 范围进行评估。实际操作中,可能需要使用 SAQ D for Merchants,也可以改用支付服务商提供的托管支付页面、重定向页面或移动 SDK,以缩小合规范围。
iframe 与 Direct Post 的区别
两种方案都能让卡数据绕过商户服务器,但商户承担的责任范围不同。
托管 iframe
支付表单中的敏感字段及相关页面元素由符合 PCI DSS 要求的支付服务商提供,卡数据通过 iframe 直接发送给服务商。商户页面无法访问这些字段的原始值。
如果同时满足其他资格条件,这类架构通常更接近 SAQ A,而非 SAQ A-EP。最终能否使用 SAQ A,还要看支付页面各元素来自哪里、商户能否影响卡数据处理,以及是否满足当前版本问卷规定的全部资格条件。
Direct Post
支付表单由商户网站生成,但提交目标是支付服务商:
<form method="post" action="https://payments.example-psp.com/charge">
<input name="card_number" autocomplete="cc-number">
<input name="expiry" autocomplete="cc-exp">
<input name="cvv" autocomplete="cc-csc">
<button type="submit">Pay</button>
</form>
这种结构下,商户服务器可能收不到卡数据,但表单代码仍由商户控制。攻击者一旦篡改网页,便可以修改 action、添加事件处理代码,或者复制输入内容。因此,商户网站及相关系统仍会在一定程度上处于 PCI DSS 范围内。
这也是 Direct Post 通常对应 SAQ A-EP,而非 SAQ A 的原因。
为什么原生控件不是自动例外
原生控件确实不会被网页中的第三方 JavaScript 直接影响,但这只排除了一种攻击方式,并未消除支付界面遭到篡改的风险。原生移动应用仍可能面临以下问题:
- 应用发布流程或签名密钥遭到破坏;
- 构建依赖、第三方 SDK 或广告 SDK 被植入恶意代码;
- 应用遭到重打包,或者运行环境被注入、hook;
- 卡数据被写入日志、崩溃报告或分析平台;
- TLS 校验、证书验证或 API 端点配置错误;
- 原生控件中的内容在发送给 PSP 前被应用代码读取或复制;
- 截屏、辅助功能、覆盖层以及受感染设备带来的风险。
因此,“不使用 JavaScript”并不是 SAQ A-EP 的资格标准。PCI DSS 关注卡数据如何流动、系统由谁控制,以及哪些组件能够影响支付过程,而不是只看 UI 控件使用 HTML 还是原生方式实现。
如何判断适用范围
1. 画出完整的数据流
至少要确认以下问题:
- 卡号、有效期和安全码在哪里输入?
- 哪个组件创建并控制这些输入字段?
- 应用代码能否读取卡数据明文?
- 数据首先发送到商户系统还是 PSP?
- 商户后端、日志、监控和分析系统是否可能接触卡数据?
- 支付服务商是否对相关服务持有有效的 PCI DSS 合规证明?
- 是否使用 WebView?其中的支付内容由谁托管?
“直接发送给 PSP”只能说明商户服务器可能不传输卡数据,不能单独用来确定 SAQ 类型。
2. 对照实际架构
| 移动支付实现 | 可能的合规方向 |
|---|---|
| 系统浏览器打开 PSP 完全托管的支付页面 | 满足全部条件时,可能适用 SAQ A |
| WebView 加载 PSP 完全托管的支付页面 | 需要额外确认,WebView、页面控制权和 SDK 行为都可能影响范围 |
| PSP SDK 提供商户无法读取明文的托管字段或支付组件 | 可能缩小范围,但不能只凭“使用 SDK”确定 SAQ 类型 |
| 商户原生控件收集卡数据,应用直接调用 PSP API | 通常不能自行认定适用 SAQ A-EP,可能需要范围更广的评估 |
| 卡数据先发送到商户 API,再转发给 PSP | 商户系统存储、处理或传输卡数据,通常不符合 SAQ A 或 A-EP 的基本方向 |
3. 取得书面确认
应将架构图和数据流提交给以下任意一方确认:
- 收单机构;
- 支付品牌;
- 合格安全评估机构(QSA);
- 支付服务商的 PCI 合规团队。
需要问清楚的不是“Direct Post 是否支持移动端”,而是:
对于由商户原生移动应用创建输入控件、应用可处理卡数据并将其直接提交给 PSP 的架构,在指定 PCI DSS 版本下,应使用哪一种 SAQ 或其他合规报告方式?
最好取得书面答复,不要只根据销售文档或通用集成说明作出判断。
更稳妥的移动端实现
如果希望尽量缩小 PCI DSS 范围,可以优先让 PSP 托管卡数据输入和令牌化过程。以下代码仅作示意,具体 API 应以支付服务商的正式 SDK 为准:
// 示意代码:支付字段和 tokenization 由 PSP SDK 管理。
// 不代表任何特定 PSP 的真实 API。
let paymentComponent = PSPHostedPaymentComponent(configuration: config)
paymentComponent.present(from: viewController) { result in
switch result {
case .success(let paymentToken):
merchantAPI.confirmPayment(token: paymentToken)
case .failure(let error):
handlePaymentError(error)
}
}
商户后端只接收不可逆或用途受限的支付令牌:
POST /api/orders/confirm-payment
Content-Type: application/json
{
"order_id": "ORD-12345",
"payment_token": "tok_example"
}
判断依据不在于变量是否命名为 token,而在于卡数据是否确实由 PSP 控制的组件采集并直接完成令牌化,以及商户应用和后端能否取得卡数据明文。
应避免自行实现以下流程,再仅凭请求直接发往 PSP,就认定已经符合 SAQ A-EP:
// 高范围示意:商户应用可以读取明文卡数据。
let payload = [
"card_number": cardNumberTextField.text,
"expiry": expiryTextField.text,
"cvv": cvvTextField.text
]
sendDirectlyToPSP(payload)
即使 sendDirectlyToPSP 完全不经过商户后端,应用本身仍然处理并传输了卡数据。
版本与表述上的注意事项
问题引用的是 PCI DSS 3.2.1 时期的 SAQ 和电子商务指导材料。该版本已不是当前评估工作的默认依据。后续 PCI DSS 版本对电子商务脚本、支付页面安全和 SAQ 资格条件作出了调整。
旧文件可以帮助理解 Direct Post 为什么是 A-EP 的典型场景,但不能直接用来确定当前移动应用的合规分类。实际评估必须采用收单机构要求的 PCI DSS 和 SAQ 版本,并逐条满足该版本首页列出的全部资格条件。
结论如下:
- Direct Post 不限于 iframe,也可能对应 SAQ A-EP;
- SAQ A-EP 中典型的 Direct Post 属于浏览器电子商务模型;
- 使用原生控件不会自动构成例外;
- 如果原生应用能够读取并提交卡数据明文,不能只因数据没有经过商户服务器,就自行选择 SAQ A-EP;
- 最终采用哪种报告方式,应由收单机构或支付品牌根据具体架构确认。
备注:内容仅供参考。
