PAYATHON 2026

支付宝网页支付h5_request_token被提取的安全问题

支付阿杰

结论

提取出 h5_request_token,不代表支付宝账户或支付密码已经被攻破,也不能仅凭这个参数认定支付宝网页支付存在安全漏洞。它更可能是网页收银台针对某次支付会话生成的临时参数,并不是商户确认到账的凭证。

这个参数仍然属于敏感会话信息,需要妥善保护。如果它能在不同设备上反复使用、长期有效,或者没有绑定订单、商户、金额和支付会话,攻击者可能用它重放收银台页面,或配合钓鱼话术诱导用户付款。具体是否构成漏洞,需要支付宝根据服务端日志和令牌校验机制进行核查,外部人员无法仅凭一个参数得出官方结论。

问题中已经公开了完整参数值,应立即停止传播,并请相关商户或支付宝确认对应的支付会话是否仍然有效。

为什么提取参数不一定能直接盗款

网页支付页面运行在用户的浏览器中,跳转地址、请求参数和网络请求通常都可能被用户或本机程序看到。安全设计不能建立在“参数不会被看见”这一前提上,而要依靠服务端验证。

安全的支付会话通常应满足这些条件:

  • 令牌随机且难以猜测;
  • 有效期较短;
  • 使用一次后失效,或有可靠的重放防护;
  • 绑定商户、订单号、金额和支付场景;
  • 修改订单信息后无法继续支付;
  • 最终付款仍需经过支付宝收银台确认,并在必要时完成身份验证;
  • 商户通过异步通知或主动查询确认支付结果,不信任浏览器跳转页面。

如果这些限制都有效,攻击者即使复制了 h5_request_token,通常也只能尝试打开同一笔支付会话,无法随意修改收款方或金额,更不能绕过用户确认直接扣款。

核查时应重点确认:复制出的令牌能否创建新的有效支付、替换交易信息、绕过付款确认,或者在原会话结束后继续使用。

建议的核查步骤

1. 立即处置已暴露的令牌

不要继续在工单、日志截图、聊天记录或公开页面中粘贴完整的 h5_request_token。提交安全报告时,只保留少量首尾字符,例如:

h5_request_token=RZ42Ob...RZ42

如果对应订单尚未完成,应取消订单或重新生成支付请求,不要继续使用已经暴露的会话。

2. 在受控环境验证令牌边界

验证时只能使用测试账号、测试订单和自有设备,不要操作他人的订单。可以检查以下情况:

  1. 把链接复制到另一台设备后,是否仍能打开;
  2. 订单取消或超时后,旧令牌是否立即失效;
  3. 支付完成后,令牌能否再次使用;
  4. 修改订单号、金额或商户参数后,服务端是否拒绝请求;
  5. 使用同一令牌发起并发请求时,是否可能产生重复交易;
  6. 页面是否清楚显示真实的商户名称、订单内容和金额;
  7. 确认支付前,是否存在异常跳转、遮罩或误导性页面。

“另一台设备能够打开收银台”本身不一定是漏洞。判断的重点是能否越权、篡改交易、绕过验证,或者造成可重复利用的资金风险。

3. 检查令牌的泄露渠道

令牌可能从以下位置泄露:

  • Web 服务器访问日志;
  • 反向代理和 CDN 日志;
  • 浏览器历史记录;
  • 页面中的第三方统计、客服或广告脚本;
  • HTTP Referer;
  • 错误监控和前端埋点;
  • 截图、录屏和聊天软件预览;
  • 恶意浏览器扩展或设备上的恶意程序。

如果令牌位于 URL 查询字符串中,应重点检查日志和第三方资源请求。商户不能擅自改变支付宝收银台规定的参数传递方式,但可以避免在自己的系统中重复记录或传播完整地址。

例如,业务日志可以只记录该参数是否存在,不保存参数值:

const url = new URL(requestUrl);
const hasH5RequestToken = url.searchParams.has("h5_request_token");

logger.info({
  path: url.pathname,
  hasH5RequestToken
});

如果排障时必须记录跳转地址,可以先进行脱敏:

function redactPaymentUrl(rawUrl) {
  const url = new URL(rawUrl);
  if (url.searchParams.has("h5_request_token")) {
    url.searchParams.set("h5_request_token", "[REDACTED]");
  }
  return url.toString();
}

logger.info({
  redirectUrl: redactPaymentUrl(requestUrl)
});

也不要把完整的支付 URL 发送给统计平台:

analytics.track("payment_redirect", {
  provider: "alipay",
  path: new URL(paymentUrl).pathname
  // 不上传 paymentUrl、h5_request_token 或其他支付参数
});

4. 商户必须在服务端确认支付结果

浏览器返回的成功页面、前端状态和 h5_request_token 都不能作为到账依据。商户应验证支付宝异步通知的签名,同时核对通知中的订单号、商户身份、金额和交易状态。

下面是 Java SDK 常见的验签形式。实际参数名称和 SDK 调用方式,应以商户当前接入的支付宝开放平台文档为准:

boolean signVerified = AlipaySignature.rsaCheckV1(
    params,
    alipayPublicKey,
    charset,
    signType
);

if (!signVerified) {
    throw new SecurityException("Invalid Alipay notification signature");
}

验签通过后,还要完成业务校验:

if (!expectedAppId.equals(params.get("app_id"))) {
    throw new SecurityException("Unexpected app_id");
}

if (!expectedOrderNo.equals(params.get("out_trade_no"))) {
    throw new SecurityException("Unexpected order number");
}

if (expectedAmount.compareTo(
        new BigDecimal(params.get("total_amount"))) != 0) {
    throw new SecurityException("Unexpected payment amount");
}

if (!"TRADE_SUCCESS".equals(params.get("trade_status"))
        && !"TRADE_FINISHED".equals(params.get("trade_status"))) {
    throw new SecurityException("Payment is not successful");
}

更新订单状态时还要保证幂等,防止重复通知引起重复发货或重复记账。遇到异常订单,可以通过支付宝提供的交易查询接口再次核实,不能只相信客户端提交的结果。

用户侧如何降低诈骗风险

进入网页收银台后,用户应确认:

  • 浏览器打开的是支付宝官方受信任域名,HTTPS 证书正常;
  • 页面显示的商户名称、商品或订单信息、金额与预期一致;
  • 没有人要求自己提供支付链接、验证码、付款码或共享屏幕;
  • 没有在陌生人的远程控制下完成支付;
  • 付款后通过支付宝账单核对收款方,不相信对方发送的“支付成功”截图。

即使打开的确实是支付宝收银台,攻击者仍可能通过话术诱导用户为错误的订单付款。真实的支付页面不能证明联系用户的人可信。

如何向官方报告

建议通过支付宝官方安全响应或客服渠道提交问题,并附上以下信息:

  • 问题发生的时间和所在时区;
  • 商户订单号和支付宝交易号,其中的敏感字段应脱敏;
  • 支付跳转的完整流程及来源平台;
  • 浏览器、操作系统和网络环境;
  • 令牌能否跨设备使用、重复使用,或在支付完成后继续使用;
  • 订单取消、超时和完成后的测试结果;
  • 页面显示的商户和金额能否被篡改;
  • 脱敏后的请求记录、录屏或截图;
  • 可以证明实际安全影响的最小复现步骤。

不要公开真实令牌、Cookie、授权码、支付密码、短信验证码或完整付款链接。未经授权,也不要对支付宝生产系统进行批量请求、并发重放或自动化扫描。

注意事项

h5_request_token 的具体用途、有效期和绑定规则属于支付宝服务端的实现细节。在缺少官方文档、服务端日志或受控测试结果时,既不能断言它已经造成支付绕过,也不能断言它完全没有风险。

判断是否存在安全漏洞,要看实际影响:能否越权访问他人订单、篡改收款信息、绕过用户确认、重复使用支付会话,或造成未经授权的资金操作。仅能查看或复制浏览器中的参数,通常不足以证明存在漏洞,但仍可作为敏感信息泄露问题提交给官方核查。

备注:内容仅供参考。