PAYATHON 2026

迁移支付处理商时如何安全迁移支付卡信息?

支付老李

明确结论

不要自行保存完整卡号,也不要设计让支付卡数据经过自有服务器”导出再上传”的流程。对大多数订阅业务来说,下面的方案更容易控制成本和风险:

  1. 使用支付处理商提供的托管支付页面、Hosted Fields 或客户端令牌化组件收集卡信息。
  2. 只保存支付处理商返回的 customer_id、payment_method_id 等无法直接用于支付的引用。
  3. 签约前确认处理商是否支持合规的 processor-to-processor card data migration。
  4. 更换处理商时,由旧处理商通过加密通道将卡数据直接交给新处理商,商户系统不接触明文 PAN。
  5. 如果业务非常重视可迁移性,可以考虑独立的 PCI DSS 合规支付数据保险库或支付编排平台,同时评估费用、责任边界和处理商兼容性。

普通支付令牌通常只能在签发它的处理商内部使用,不能直接交给另一家处理商。迁移能否顺利完成,主要取决于处理商的合同条款、数据导出政策,以及新旧处理商是否愿意配合实施合规迁移。

为什么不应自行保存卡信息

完整主账号 PAN(Primary Account Number)属于支付卡数据。系统只要存储、处理或传输 PAN,就会显著扩大 PCI DSS 的适用范围,通常还要承担以下工作:

  • 网络隔离、访问控制、密钥管理和日志审计
  • 漏洞扫描、渗透测试和补丁管理
  • 数据保留与安全删除机制
  • 服务商和人员权限管理
  • PCI DSS 合规验证及可能的现场评估
  • 数据泄露后的通知、取证、罚款和赔付风险

具体成本取决于交易量、收单机构要求、系统架构和适用的 SAQ 类型,不能简单归结为某个固定金额。对早期订阅项目而言,自建卡数据保险库通常并不划算。

还要注意,CVV/CVC 属于敏感认证数据。即使经过加密,也不得在授权完成后保存。迁移订阅支付通常也不需要迁移 CVV。

推荐的系统设计

1. 让浏览器或移动端直接提交给支付处理商

使用处理商提供的 Hosted Checkout、Hosted Fields 或官方客户端 SDK。卡号应从用户设备直接发送给处理商,不经过自己的应用服务器。

后端只接收令牌化后的标识,例如:

{
  "provider": "processor_a",
  "provider_customer_id": "cus_123",
  "provider_payment_method_id": "pm_456",
  "card_metadata": {
    "brand": "visa",
    "last4": "4242",
    "exp_month": 12,
    "exp_year": 2028
  }
}

brand、last4 和有效期可以用于界面展示和到期提醒,但不能作为可迁移的支付凭证。数据库中不要设置 card_number、pan、cvv 或磁道数据字段。

这类集成通常能缩小 PCI DSS 范围,但不等于完全免除相关责任。最终适用的 SAQ 类型和验证要求,需要由收单机构、支付处理商或合格的 PCI 顾问结合实际数据流确认。

2. 在业务模型中隔离处理商标识

不要将某家处理商的 customer ID 用作内部用户主键。应为支付资料建立独立映射:

CREATE TABLE payment_profiles (
    id UUID PRIMARY KEY,
    account_id UUID NOT NULL,
    provider VARCHAR(50) NOT NULL,
    provider_customer_id VARCHAR(255) NOT NULL,
    provider_payment_method_id VARCHAR(255),
    migration_status VARCHAR(30) NOT NULL DEFAULT 'not_started',
    created_at TIMESTAMP NOT NULL,
    updated_at TIMESTAMP NOT NULL,
    UNIQUE (provider, provider_customer_id)
);

订阅记录也应区分内部订阅和处理商订阅:

CREATE TABLE subscriptions (
    id UUID PRIMARY KEY,
    account_id UUID NOT NULL,
    payment_profile_id UUID NOT NULL,
    provider_subscription_id VARCHAR(255),
    status VARCHAR(30) NOT NULL,
    current_period_end TIMESTAMP,
    FOREIGN KEY (payment_profile_id) REFERENCES payment_profiles(id)
);

这样,迁移时可以为同一账户增加新的处理商映射,不必修改用户身份、套餐或业务订阅的主键。

3. 签约前确认可迁移条款

不要只问”是否支持导出客户”,还应书面确认以下事项:

  • 是否支持向另一家 PCI DSS 合规服务商迁移完整 PAN 和有效期
  • 是否收取导出费、项目费或最低服务费
  • 导出是否需要收单机构或卡组织批准
  • 支持哪些传输方式和加密格式
  • 是否要求新处理商提供 PCI DSS 合规证明或 Attestation of Compliance
  • 能否迁移账单地址、持卡人姓名和订阅相关元数据
  • 能否迁移 stored credential、MIT/CIT 等交易属性
  • 原处理商的专有 token 是否会失效
  • 终止合同后还可以在多长时间内申请迁移
  • 迁移完成后旧数据何时删除,以及如何提供删除证明
  • 如果处理商被收购、停止服务或账户被冻结,数据迁移权是否仍然有效

最好将这些内容写入合同或数据可移植性附件。销售人员的口头承诺不足以保障未来迁移。

实际迁移流程

第一步:与新处理商进行兼容性评估

先让新处理商确认其能够接收旧处理商的数据。双方通常会成立专门的迁移项目,约定字段格式、加密方式、传输通道和验证流程。

不要让旧处理商将包含完整卡号的 CSV 文件发送到普通业务邮箱,也不要先下载到开发人员电脑,再由开发人员上传。即使文件设置了密码,这种做法也可能扩大商户的 PCI DSS 范围,并增加不必要的泄露风险。

第二步:建立 ID 对照关系

导入完成后,新处理商通常会返回旧记录与新 token 或 payment method ID 之间的映射。具体格式由双方约定,例如:

legacy_customer_ref,new_customer_id,new_payment_method_id,status
acct_1001,cus_new_71,pm_new_91,imported
acct_1002,cus_new_72,,failed

导入程序只处理这些引用,不接触 PAN:

async function applyMigrationResult(row, db) {
  if (row.status !== "imported") {
    await db.paymentProfiles.markMigrationFailed(
      row.legacy_customer_ref
    );
    return;
  }

  await db.transaction(async (tx) => {
    await tx.paymentProfiles.create({
      accountId: row.legacy_customer_ref,
      provider: "processor_b",
      providerCustomerId: row.new_customer_id,
      providerPaymentMethodId: row.new_payment_method_id,
      migrationStatus: "imported"
    });

    await tx.paymentProfiles.markMigrationCompleted(
      row.legacy_customer_ref,
      "processor_a"
    );
  });
}

实际实现还应验证文件签名、记录批次号、限制操作权限,并保证重复导入时具有幂等性。日志中不得记录任何可能包含 PAN 的原始响应。

第三步:小批量验证

先迁移内部测试账户,再迁移一小批真实账户,检查以下事项:

  • 新 payment method 能否用于订阅续费
  • 币种、金额和税费是否一致
  • 是否正确标记为商户发起交易 MIT
  • 拒付、退款和争议流程是否正常
  • Webhook 是否会重复或乱序到达
  • 失败支付是否进入正确的重试和催收流程

不能只凭”导入成功”判断迁移已经完成。部分卡片可能已经过期、被换卡、受地区限制,或需要重新认证。

第四步:双系统过渡

迁移期间,可以短时间并行维护两套处理商映射,但必须防止同一账期重复扣款。路由判断可以写成:

function selectBillingProvider(subscription) {
  if (
    subscription.newProfile?.migrationStatus === "verified" &&
    subscription.cutoverEnabled === true
  ) {
    return "processor_b";
  }

  return "processor_a";
}

切换状态应由可审计且幂等的迁移任务控制,不能根据请求时间或随机比例临时决定。旧处理商中的订阅,应在确认新处理商续费成功或到达约定切换点后再取消。

第五步:处理无法迁移的账户

即使处理商支持迁移,也不能假设成功率是 100%。应为失败账户准备渐进式补录方案:

  • 用户登录后提示更新付款方式
  • 在卡片到期或下一次付款失败时要求重新录入
  • 通过邮件和站内通知提前提醒
  • 提供合理的宽限期
  • 对高价值账户安排人工跟进

相比在某一天要求所有用户重新订阅,这种做法更稳妥,也能减少对收入的影响。

独立支付保险库是否值得使用

独立的 PCI DSS 合规保险库可以将卡片 token 与具体处理商解耦,并按规则向多个处理商提供支付凭证。这类方案通常适用于以下情况:

  • 需要在多个收单机构之间动态路由
  • 需要覆盖多个国家、币种或高可用场景
  • 处理商切换是一项明确且频繁的业务需求
  • 交易规模足以承担平台费用和集成成本

不过,使用”独立 token”并不代表商户自动脱离 PCI DSS 范围。仍需确认卡数据是否经过商户服务器、保险库如何向处理商提供数据、哪些组件由商户控制,以及发生泄露时各方如何分担责任。

也不要把”支付编排”等同于”可移植保险库”。有些平台虽然可以连接多个处理商,但底层仍然使用各处理商的专有 token,未必能够迁移已有卡片。

网络令牌与账户更新服务

部分处理商支持卡组织网络令牌或 account updater,可以在实体卡换号、到期或补发后更新付款凭证。这有助于提高订阅续费成功率,但不能据此认定处理商迁移问题已经解决。

网络令牌能否迁移,以及 token requestor 身份和加密密钥之间的关系,取决于具体架构和参与方。迁移前必须由新旧处理商明确确认,不能将现有网络令牌当作普通 PAN 直接复制。

关键注意事项

  • 不要存储 CVV/CVC,即使加密后也不行。
  • 不要认为加密 PAN 就能免除 PCI DSS 义务。如果系统可以解密或控制密钥,通常仍在合规范围内。
  • 不要把处理商 token 当作行业通用 token。
  • 不要通过邮件、工单附件或开发人员电脑传递卡数据。
  • 不要在日志、异常追踪、分析平台或客服系统中记录完整卡号。
  • 不要只迁移卡片,而忽略 stored credential consent、MIT/CIT 标记、账单协议和用户授权证据。
  • 旧的用户授权是否足以覆盖新处理商,取决于合同内容、地区法律、卡组织规则和新处理商政策,需要由专业合规或法律人员确认。
  • 正式迁移前应检查退款、争议和历史交易查询能力。旧交易通常仍需通过旧处理商退款或举证。
  • 准备回滚和对账方案,避免漏扣或重复扣款。

对大多数订阅项目而言,较为现实的方案是”处理商托管收卡 + 商户保存 token + 通过合同保障处理商之间直接迁移”。这种方案无法保证任意两家处理商之间都能无缝迁移,但可以在商户不自行持有完整卡数据的前提下,将未来切换的成本和风险控制在合理范围内。

备注:内容仅供参考。