Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

【安全】WxPayValidator 未校验微信支付 V3 应答时间戳(Wechatpay-Timestamp),缺少重放攻击防护

已關閉
#4,133 2 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
3/5
預估耗時
1-2 天
新手友好度
68/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
java

研究方向

Start with weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayValidator.java, especially validate(CloseableHttpResponse), and trace its call from SignatureExec.executeWithSignature. Verify the timestamp freshness behavior against the stated five-minute requirement and check the handling of non-JSON 2xx responses; the work is done when expired responses are rejected while valid signed responses remain accepted.

由索引模型根據 Issue 內容生成。

描述

【微信支付 V3】WxPayValidator 未校验应答时间戳,缺少重放攻击防护(Wechatpay-Timestamp 未做新鲜度校验)

漏洞类型:重放攻击防护缺失
影响组件:weixin-java-pay / WxPayValidator
风险场景:链路窃听、中间人重放合法应答

1. 环境

项目 内容
SDK 版本 binarywang/WxJava develop 分支(4.8.x 范围内),含 WxPayValidator 的所有已发布 4.x 版本均受影响
模块 weixin-java-pay
Java 版本 JDK 8+
接入方式 微信支付 V3(WxPayService + AutoUpdateCertificatesVerifier / CertificatesVerifier,WxPayV3HttpClientBuilder 构建的 CloseableHttpClient)

2. 复现步骤

  1. 按官方方式初始化微信支付 V3 的 WxPayService,使用 WxPayV3HttpClientBuilder 拿到 HttpClient(内部通过 SignatureExec 对 2xx 应答做 WxPayValidator.validate)。
  2. 调用任意 V3 接口(如“查询订单”),正常拿到应答。
  3. 攻击者截获该次应答,包含:
    • Wechatpay-Timestamp
    • Wechatpay-Nonce
    • Wechatpay-Signature
    • Wechatpay-Serial
    • JSON body
  4. 在数分钟、数小时或任意时间后,将此应答原样重放给调用方,或由链路上的中间人重放。

3. 期望行为

依据微信支付 V3 签名验证规范,商户侧应校验 Wechatpay-Timestamp 与本地时间之差不超过 5 分钟;超时的应答应判定为验签失败,以提供重放攻击防护。

4. 实际行为

WxPayValidator.validate(...) 只校验四个头部是否存在,并做密码学验签,从不校验时间戳新鲜度。

方法内明确留有:

// todo: check timestamp

但未实现。

因此,重放的旧应答仍被判定为验签通过,SignatureExec 不会抛出异常,调用方拿到被重放的数据。

5. 根因分析

  • 文件:weixin-java-pay/src/main/java/com/github/binarywang/wxpay/v3/auth/WxPayValidator.java
  • 方法:validate(CloseableHttpResponse response)(约第 27–34 行)
  • 相关代码:
// todo: check timestamp
if (timestamp == null || nonce == null || serialNo == null || sign == null) {
  return false;
}
String message = buildMessage(response);
return verifier.verify(serialNo.getValue(), message.getBytes(StandardCharsets.UTF_8), sign.getValue());
  • 原因:
    • verifier.verify(...) 仅使用平台证书对 timestamp\nnonce\nbody\n 做 RSA 验签。
    • 时间戳本身被当作“参与签名的字符串”,而不是“需校验的时间量”。
    • 缺失类似 |当前秒 - Long.parseLong(timestamp)| <= 300 的新鲜度判断,导致重放攻击防护缺位。

6. 影响

在存在链路窃听或中间人的场景下,合法应答可被重放并被判为有效,违反微信支付 V3 防重放要求。

同时,validate 对 Content-Type 非 application/json 的 2xx 应答直接 return true 跳过验签(同方法首行),进一步放大风险。

7. 建议修复方向

在 validate 中补充时间戳新鲜度校验,例如:

long wechatTimestamp = Long.parseLong(timestamp.getValue());
long diff = Math.abs(System.currentTimeMillis() / 1000 - wechatTimestamp);
if (diff > 300) {
  log.warn("微信支付应答时间戳超时,疑似重放攻击:{} 秒", diff);
  return false;
}

并建议将首行的“非 JSON 直接 return true”改为:

  • 对未知或非 JSON 的 2xx 应答默认拒绝;或
  • 至少记录告警,避免绕过验签。

8. 参考

  • 微信支付 V3 签名验证规范:应答/回调需校验 Wechatpay-Timestamp 与本地时间差不超过 5 分钟,防止重放。
  • 相关代码路径:SignatureExec.executeWithSignature(...) -> validator.validate(response)。
主要語言
Java
星號
33.1k
分支
9.1k
平均合併
3 天 11 小時
30 天內合併 PR
10

環境準備

  • 沒有 Dockerfile 或 Docker Compose 檔案
  • 沒有 Pull Request 範本
  • 閱讀貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

binarywang/WxJava 的其他 Issue

查看 binarywang/WxJava 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。