支付宝网页支付h5_request_token被提取的安全问题
结论
提取出 h5_request_token,不代表支付宝账户或支付密码已经被攻破,也不能仅凭这个参数认定支付宝网页支付存在安全漏洞。它更可能是网页收银台针对某次支付会话生成的临时参数,并不是商户确认到账的凭证。
这个参数仍然属于敏感会话信息,需要妥善保护。如果它能在不同设备上反复使用、长期有效,或者没有绑定订单、商户、金额和支付会话,攻击者可能用它重放收银台页面,或配合钓鱼话术诱导用户付款。具体是否构成漏洞,需要支付宝根据服务端日志和令牌校验机制进行核查,外部人员无法仅凭一个参数得出官方结论。
问题中已经公开了完整参数值,应立即停止传播,并请相关商户或支付宝确认对应的支付会话是否仍然有效。
为什么提取参数不一定能直接盗款
网页支付页面运行在用户的浏览器中,跳转地址、请求参数和网络请求通常都可能被用户或本机程序看到。安全设计不能建立在“参数不会被看见”这一前提上,而要依靠服务端验证。
安全的支付会话通常应满足这些条件:
- 令牌随机且难以猜测;
- 有效期较短;
- 使用一次后失效,或有可靠的重放防护;
- 绑定商户、订单号、金额和支付场景;
- 修改订单信息后无法继续支付;
- 最终付款仍需经过支付宝收银台确认,并在必要时完成身份验证;
- 商户通过异步通知或主动查询确认支付结果,不信任浏览器跳转页面。
如果这些限制都有效,攻击者即使复制了 h5_request_token,通常也只能尝试打开同一笔支付会话,无法随意修改收款方或金额,更不能绕过用户确认直接扣款。
核查时应重点确认:复制出的令牌能否创建新的有效支付、替换交易信息、绕过付款确认,或者在原会话结束后继续使用。
建议的核查步骤
1. 立即处置已暴露的令牌
不要继续在工单、日志截图、聊天记录或公开页面中粘贴完整的 h5_request_token。提交安全报告时,只保留少量首尾字符,例如:
h5_request_token=RZ42Ob...RZ42
如果对应订单尚未完成,应取消订单或重新生成支付请求,不要继续使用已经暴露的会话。
2. 在受控环境验证令牌边界
验证时只能使用测试账号、测试订单和自有设备,不要操作他人的订单。可以检查以下情况:
- 把链接复制到另一台设备后,是否仍能打开;
- 订单取消或超时后,旧令牌是否立即失效;
- 支付完成后,令牌能否再次使用;
- 修改订单号、金额或商户参数后,服务端是否拒绝请求;
- 使用同一令牌发起并发请求时,是否可能产生重复交易;
- 页面是否清楚显示真实的商户名称、订单内容和金额;
- 确认支付前,是否存在异常跳转、遮罩或误导性页面。
“另一台设备能够打开收银台”本身不一定是漏洞。判断的重点是能否越权、篡改交易、绕过验证,或者造成可重复利用的资金风险。
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 的具体用途、有效期和绑定规则属于支付宝服务端的实现细节。在缺少官方文档、服务端日志或受控测试结果时,既不能断言它已经造成支付绕过,也不能断言它完全没有风险。
判断是否存在安全漏洞,要看实际影响:能否越权访问他人订单、篡改收款信息、绕过用户确认、重复使用支付会话,或造成未经授权的资金操作。仅能查看或复制浏览器中的参数,通常不足以证明存在漏洞,但仍可作为敏感信息泄露问题提交给官方核查。
备注:内容仅供参考。
