【安全】WxPayValidator 未校验微信支付 V3 应答时间戳(Wechatpay-Timestamp),缺少重放攻击防护
Los mantenedores suelen responder en 2 días
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 3/5
- Tiempo estimado
- 1-2 días
- Aptitud para principiantes
- 68/100
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
【微信支付 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. 复现步骤
- 按官方方式初始化微信支付 V3 的
WxPayService,使用WxPayV3HttpClientBuilder拿到HttpClient(内部通过SignatureExec对 2xx 应答做WxPayValidator.validate)。 - 调用任意 V3 接口(如“查询订单”),正常拿到应答。
- 攻击者截获该次应答,包含:
Wechatpay-TimestampWechatpay-NonceWechatpay-SignatureWechatpay-Serial- JSON body
- 在数分钟、数小时或任意时间后,将此应答原样重放给调用方,或由链路上的中间人重放。
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)。
- Lenguaje dominante
- Java
- Estrellas
- 33.1k
- Forks
- 9.1k
- Merge medio
- 3 d 19 h
- PR fusionados (30 d)
- 9
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Sin plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de binarywang/WxJava
-
v3支付接口签名支持国密算法Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 18/100
binarywang/WxJava#4141 ·
Los mantenedores suelen responder en 2 días
-
支持不携带access_token请求特定接口Posiblemente ocupada @binarywang la tomó hace 3 días. Abierto
Dificultad 3/5 1-2 días Aptitud para principiantes 57/100
binarywang/WxJava#4138 · 1 comentario ·
Los mantenedores suelen responder en 2 días
-
微信支付功能增加对支付品牌的支持Posiblemente ocupada @binarywang la tomó hace 4 días. Abierto
Dificultad 5/5 Más de una semana Aptitud para principiantes 28/100
binarywang/WxJava#3972 ·
Los mantenedores suelen responder en 2 días
-
欢迎贡献过代码的朋友加入微信开发组专群,以便享受多重福利待遇Abiertopinned
Dificultad 5/5 Más de una semana Aptitud para principiantes 1/100
binarywang/WxJava#3057 ·
Los mantenedores suelen responder en 2 días
-
WxJava 应用案例收集Quizá libre de nuevo @binarywang la tomó hace 2972 días y no hay ningún pull request abierto. Abiertopinned
binarywang/WxJava#729 · 84 comentarios · 43 reacciones · 1 asignado ·
Los mantenedores suelen responder en 2 días
Todos los issues de binarywang/WxJava
Issues similares
-
Dificultad 1/5 Menos de una hora Aptitud para principiantes 90/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 82/100
apache/rocketmq-dashboard#6896 ·
Los mantenedores suelen responder en 3 días
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 67/100
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
OpenIntegrationEngine/engine#496 ·
Los mantenedores suelen responder en 1 día
-
enhancement good first issue
Dificultad 2/5 1-3 horas Aptitud para principiantes 76/100
SasanLabs/VulnerableApp#836 ·
Los mantenedores suelen responder en 1 día