PAYATHON 2026

支付宝APP支付数据被抓包用于诈骗,平台A如何防范

支付阿杰

明确结论

只隐藏或加密支付宝 APP 支付的 orderString,无法彻底阻止平台 B 抓包后诱导第三方付款。更有效的做法,是把支付订单设计成一次性、短时有效、不可转移的业务凭证,并将下单用户、登录设备、业务订单、支付宝交易、商品交付对象和提现账户串成一条完整链路。

平台 A 至少需要做到以下几点:

  • 支付订单由服务端创建,金额、商品、收款方和业务参数不能由客户端决定。
  • 支付订单只能由创建订单的账号使用,并设置较短的有效期。
  • 支付结果只以支付宝服务端异步通知或主动查单结果为准,不信任客户端回传。
  • 严格验签,同时核对 app_id、商户身份、金额、币种、订单号和交易状态。
  • 同一订单、支付凭证和支付宝交易号只能入账一次。
  • 付款人与消费、兑换或提现主体不一致时,限制相关操作或转人工审核。
  • 对高风险虚拟商品、余额、兑换和提现延迟交付,避免支付后立即套现。
  • 保存完整证据链,并建立快速止付、权益冻结、退款和投诉响应机制。

还要正视一个限制:普通支付宝 APP 支付可能由另一个支付宝账号完成,也可能存在他人代付。平台 A 通常无法仅凭客户端参数,可靠证明付款支付宝账号就是平台账号本人。如果业务必须禁止第三方付款,就要结合支付宝当前开放能力、实名信息、协议约束和业务风控共同处理。具体能够取得哪些付款人字段,应以平台 A 已签约产品和支付宝开放平台当期文档为准。

为什么支付参数被抓包后仍可能付款

支付宝 APP 支付通常由平台 A 的服务端创建订单,再将签名后的 orderString 返回 App,由 App 调起支付宝。这个字符串的签名用于确认商户订单参数没有被篡改,但不能保证它只在平台 A 的 App、原设备或原账号中使用。

因此,下面这些措施不能作为主要防线:

  • 只使用 HTTPS;
  • 对 orderString 再做一层客户端加密;
  • 混淆 App 或隐藏接口;
  • 校验客户端上报的设备号;
  • 收到客户端的“支付成功”结果后立即发货。

HTTPS 可以防止正常传输链路被窃听,却拦不住已经控制终端、Hook、代理环境或恶意客户端的人获取支付参数。只要客户端能够解密或使用某段数据,攻击者通常也有办法将其复制出来。

防护重点应放在支付后的业务链路上。即使支付串被复制,攻击者也不能低成本完成消费、兑换和提现。

一、支付订单必须由服务端创建

客户端只提交商品标识、数量等必要信息,由服务端根据数据库中的商品价格和活动规则计算应付金额。不能让客户端提交最终金额、支付宝收款参数或任意 subject,然后由服务端直接签名。

创建订单时,应记录:

  • 内部订单号 out_trade_no;
  • 下单账号 user_id;
  • 商品、数量以及服务端计算的金额;
  • 创建时间和过期时间;
  • 登录会话、设备风险标识和 IP;
  • 订单用途,例如实物购买、虚拟充值或兑换;
  • 订单状态和交付状态;
  • 随机业务流水号。

out_trade_no 必须全局唯一且不可预测,不要使用连续自增 ID。订单还要设置合理的支付宝支付超时时间,平台 A 内部也应同步设置过期状态。

订单过期后,不能因为迟到的客户端请求而直接恢复。如果支付宝侧已经完成支付,应进入主动查单、退款或人工处理流程。

二、把订单与下单用户和业务用途绑定

这种绑定必须保存在服务端,不能只留在客户端。支付结果入账时,应从数据库读取订单原始记录。后续权益只能发放给记录中的 user_id,不能由回调参数或客户端重新指定受益账号。

例如,创建充值订单时就要确定充值账户:

out_trade_no -> user_id -> wallet_id -> product_id -> amount

支付完成后,不能接受下面这种请求:

{
  "out_trade_no": "原订单号",
  "credit_to_user": "另一个用户",
  "withdraw_account": "新收款账户"
}

如果业务允许赠送、代充或转让,应将其设计成独立流程,并加入接收方确认、实名校验、额度限制和冷静期。不能复用普通支付订单来绕过风控。

支付参数的获取也应受到限制:

  • 只有创建订单的有效登录会话可以获取支付参数;
  • 同一订单不能反复生成多份支付参数;
  • 获取支付参数前,再次检查订单所有者、订单状态和有效期;
  • 风险设备、批量账号或异常 IP 需要接受二次验证;
  • 接口按账号、设备、IP 和订单设置频率限制。

这些措施无法阻止攻击者展示已经获取的支付串,但可以减少批量盗取和转卖订单的情况。

三、不要信任客户端的支付结果

客户端 SDK 返回的 resultStatus 只能用于界面提示,不能作为发货、充值、兑换或提现的依据。客户端结果可能被伪造,网络异常时也可能与支付宝的实际交易状态不一致。

正确的处理流程是:

  1. 客户端发起支付。
  2. 支付宝向平台 A 的服务端发送异步通知。
  3. 平台 A 验证签名并校验通知内容。
  4. 必要时通过支付宝服务端交易查询接口主动查单。
  5. 在数据库事务中将订单从“待支付”改为“已支付”。
  6. 风控审核通过后,再交付商品或权益。
  7. 向支付宝通知接口返回约定的成功响应。

客户端轮询订单状态时,只能读取平台 A 服务端已经确认的状态。

四、严格完成回调验签和业务校验

平台 A 应使用支付宝官方 SDK,并按照已接入接口的签名规则验证异步通知。不要自行拼接参数,不要忽略字符集差异,也不能混用支付宝公钥和应用公钥。

验签通过后,还需要逐项核对:

  • app_id 是否为平台 A 的应用 ID;
  • 通知中的商户身份是否属于平台 A;
  • out_trade_no 是否存在,且对应正确的支付渠道;
  • total_amount 是否与数据库中的金额完全一致;
  • trade_status 是否属于业务允许处理的成功状态;
  • trade_no 是否已绑定其他订单;
  • 币种、订单用途等字段是否符合预期;
  • 订单是否已经关闭、退款或处理完成。

金额应使用十进制定点类型,不能用 double 比较。

下面是一段简化的 Java 示例。字段名称和 SDK 调用方式需要按照平台 A 当前使用的支付宝 SDK 版本调整:

@PostMapping("/pay/alipay/notify")
@Transactional
public String handleNotify(HttpServletRequest request) throws Exception {
    Map<String, String> params = extractAlipayParams(request);

    boolean valid = AlipaySignature.rsaCheckV1(
        params,
        alipayPublicKey,
        "UTF-8",
        "RSA2"
    );

    if (!valid) {
        return "failure";
    }

    String outTradeNo = params.get("out_trade_no");
    String tradeNo = params.get("trade_no");
    String tradeStatus = params.get("trade_status");
    String notifyAppId = params.get("app_id");
    BigDecimal paidAmount = new BigDecimal(params.get("total_amount"));

    PayOrder order = payOrderRepository.lockByOutTradeNo(outTradeNo)
        .orElseThrow(() -> new IllegalArgumentException("unknown order"));

    if (!expectedAppId.equals(notifyAppId)) {
        return "failure";
    }

    if (order.getChannel() != PayChannel.ALIPAY) {
        return "failure";
    }

    if (paidAmount.compareTo(order.getAmount()) != 0) {
        markRisk(order, "AMOUNT_MISMATCH");
        return "failure";
    }

    if (!Set.of("TRADE_SUCCESS", "TRADE_FINISHED").contains(tradeStatus)) {
        return "success";
    }

    if (payOrderRepository.existsByTradeNoAndOutTradeNoNot(
            tradeNo, outTradeNo)) {
        markRisk(order, "DUPLICATE_TRADE_NO");
        return "failure";
    }

    if (order.isPaid()) {
        return tradeNo.equals(order.getTradeNo()) ? "success" : "failure";
    }

    order.markPaid(tradeNo, Instant.now());
    riskService.submitForReview(order);

    return "success";
}

这段示例省略了商户身份、通知 ID、退款状态、异常补偿和日志脱敏等代码,不能直接当作完整的生产实现使用。业务代码也不能在验签前修改通知参数。

五、用数据库约束防止重放和重复入账

支付宝可能重复发送支付回调,攻击者也可能重放回调请求,因此接口必须支持幂等处理。

建议至少建立以下唯一约束:

CREATE UNIQUE INDEX uk_pay_order_out_trade_no
ON pay_order(out_trade_no);

CREATE UNIQUE INDEX uk_pay_order_trade_no
ON pay_order(alipay_trade_no);

CREATE UNIQUE INDEX uk_ledger_business_event
ON account_ledger(business_type, business_order_no);

更新订单时使用条件更新或行锁:

UPDATE pay_order
SET status = 'PAID',
    alipay_trade_no = :trade_no,
    paid_at = :paid_at
WHERE out_trade_no = :out_trade_no
  AND status = 'PENDING';

只有受影响行数为 1 时,才能首次生成权益。如果受影响行数为 0,应查询现有状态并按照幂等结果处理,不能再次充值或发货。

除了支付回调,创建订单、发券、记账、兑换和提现也要设置各自的幂等键。缓存锁可以辅助削峰,但不能替代数据库唯一约束。

六、识别付款人与业务用户不一致的风险

这个场景中,平台 B 的账号负责创建订单,受骗用户负责付款,支付结果随后被转化为平台 B 可以提现或转售的权益。即使交易验签完全正确,资金来源与权益受益人仍可能不是同一个人。

在合规并获得授权的前提下,平台 A 应利用支付渠道实际返回且允许使用的信息,判断付款主体与平台实名主体之间的关系。如果当前产品无法提供足够的付款人身份信息,就不能假定一致性校验已经完成,而应采用其他控制措施:

  • 高风险业务要求平台账号完成实名认证;
  • 提现账户姓名必须与平台实名信息一致;
  • 新账号、新设备或新的支付关系不能立即提现;
  • 首次大额支付后设置观察期;
  • 付款后修改手机号、实名信息或提现账户时重新验证;
  • 多个付款来源集中向同一个账号充值时,提高风险等级;
  • 同一付款来源为大量无关联平台账号付款时进行拦截;
  • 禁止余额无损转让、循环兑换或快速变现;
  • 对疑似第三方付款给出明确提示,并允许付款人在付款前取消。

平台 A 不能使用未经授权取得的个人信息,也不要在程序中认定某些可能变化的支付宝字段必然存在。能否获得买家标识、实名状态或其他信息,取决于签约产品、接口权限和监管要求。

七、虚拟商品、兑换和提现必须延迟处置

实物商品可以借助收货地址和物流提高追踪成本。余额、卡券、游戏资产、数字商品和提现能力则更容易被立即变现,需要更严格的交付策略。

可以按风险分层处理:

  • 低风险实物订单正常履约,同时保留拦截发货的能力;
  • 新用户首次购买虚拟商品时,先进行短暂审核;
  • 高额、密集或资金来源异常的支付,不立即发放可转让权益;
  • 支付所得余额与赠送余额分账记录;
  • 支付所得资金在观察期内不能提现或转赠;
  • 提现前重新校验实名、设备、手机号和收款账户;
  • 新增或更换提现账户后设置冷静期;
  • 对提现设置单笔、单日和周期累计额度;
  • 高风险提现转人工审核;
  • 收到投诉、退款申请或命中风险规则后,立即冻结未消耗权益和尚未出款的申请。

观察期和额度不能直接套用固定数值。平台 A 应根据商品可逆性、客诉率、历史损失、履约周期和正常用户行为制定规则,并在用户协议和页面中清楚说明相关限制。

八、建立覆盖完整链路的异常交易监控

只看单笔金额,往往发现不了这类诈骗。平台 A 需要关联分析账号、设备、IP、支付订单、支付宝交易、收货信息、提现账户和投诉记录。

需要重点监控的信号包括:

  • 新注册账号在短时间内连续创建多个支付订单;
  • 订单创建地、登录地和支付后操作地出现明显跳变;
  • 同一设备控制多个账号;
  • 多个账号最终向同一银行卡或收款账户提现;
  • 大量订单支付成功后立即兑换、转移或提现;
  • 订单金额高度固定,疑似由诈骗网站预设档位;
  • 支付参数获取次数、取消次数或超时次数异常;
  • 长期没有活动的账号突然出现大额交易;
  • 客诉率、退款率或渠道风控提示突然升高;
  • 同一商品被批量购买并迅速变现;
  • 支付后立即换绑设备、手机号或提现账户。

风险评分应分别作用于交易链路中的不同环节,不能只做简单封号:

低风险:正常交付
中风险:二次验证、限额、延迟交付
高风险:暂停交付、冻结可疑权益、人工审核
确认欺诈:止付或退款、封禁关联关系、保存证据

风控规则还要提供申诉和人工复核渠道,避免仅凭 IP 或异地登录等单一特征误伤正常用户。

九、投诉发生后的处置流程

收到支付宝风险提醒或付款人投诉后,平台 A 应将资金处理与账号处罚分开。先控制损失,再调查责任:

  1. 根据 out_trade_no 和 trade_no 定位支付订单。
  2. 暂停相关商品的发货、兑换和提现。
  3. 冻结由该笔支付产生的未消耗权益,不要随意冻结无关资产。
  4. 关联排查账号、设备、IP、收货地址和提现账户。
  5. 保存下单、登录、支付、回调、查单、交付和提现日志。
  6. 核实后按照支付宝流程及时举证或退款。
  7. 为确认受骗的付款人提供清晰的客服入口和处理进度。
  8. 将已经确认的诈骗特征加入后续风控规则。
  9. 复查相同攻击路径下是否还有未处置订单。

向支付宝举证时,应提交能够证明真实交易链路的材料,例如商品信息、用户操作记录、交付记录、物流信息、实名信息和风控过程。日志需要可信、时间统一且能够防止篡改,同时遵守数据最小化原则和保存期限要求。

如果商品还没有交付,主动拦截并尽快退款,通常比继续履约更能减少损失和投诉风险。退款必须通过原支付渠道完成,不能按照陌生人提供的银行卡或二维码线下转账,否则可能引发二次诈骗。

十、推荐的整体交易状态设计

订单状态不能只有“未支付”和“已支付”。可以采用下面这条状态链路:

CREATED
  -> PAYING
  -> PAID_PENDING_REVIEW
  -> PAID_APPROVED
  -> DELIVERING
  -> DELIVERED

异常分支可以包括:

EXPIRED
CLOSED
RISK_HOLD
REFUNDING
REFUNDED
DISPUTED

支付成功只表示平台收到了支付渠道的确认,不表示订单已经通过风控,也不表示相关资金可以立即提现。支付状态、业务履约状态、退款状态和提现状态应分别保存,避免用一个布尔字段控制全部流程。

注意事项

  • 日志中不要完整记录 orderString、签名、访问令牌、身份证号、手机号或银行卡号。
  • 私钥只能保存在服务端的密钥管理系统中,不能打包进 App。
  • 支付宝异步通知地址应使用 HTTPS,并处理好可用性、超时和重试问题。
  • IP 白名单只能作为辅助措施,不能替代验签。回调网络地址可能变化时,应以支付宝当期官方说明为准。
  • 主动查单用于补偿和确认状态,不能因此跳过金额、商户身份和业务订单校验。
  • 不能使用前端传来的 user_id 决定交付对象,应从服务端订单记录中读取。
  • 支付成功、记账和发货之间应使用事务、事务消息或可靠事件机制,防止只完成部分操作。
  • 风控范围不能只覆盖支付入口。兑换、转赠和提现才是攻击者完成变现的主要出口。
  • 定期使用测试账号验证重复回调、并发回调、迟到回调、金额不一致、订单过期和退款等场景。
  • 支付宝接口字段、签名算法、通知状态和退款流程的实现,应以平台 A 当前签约产品和支付宝开放平台最新文档为准。

最终目标不是保证支付串永远不会被复制,而是让复制后的订单无法转移、重复入账或立即变现。如果发生第三方付款,平台 A 也应在商品交付和资金出款前识别并拦截。这样既能保护付款人,也能减少平台 A 的实际损失,降低集中投诉导致资金冻结或账号异常的风险。

备注:内容仅供参考。