Skills

Cc Payment Callback Safety

支付回调/webhook 安全检查,防止回调伪造、重放攻击和金额篡改。

Install

npx skills add doccker/cc-use-exp --skill cc-payment-callback-safety -g -a claude-code -y
Repository
doccker/cc-use-exp1.1k
Category
Engineering
Updated
2mo ago
License
See repository
Context cost
Mediumabout 1,622 tokens
Runs scripts
No, instructions only

What it does

支付回调/webhook 安全检查,防止回调伪造、重放攻击和金额篡改。

支付回调安全规范

当系统涉及第三方支付回调(微信支付、支付宝等)或 webhook 通知时,防止伪造、篡改和重放攻击。


陷阱 #1: 回调未验证平台签名

场景: 收到支付回调后直接解密/解析并处理,未验证请求确实来自支付平台

问题根因

支付回调地址暴露在公网,任何人都可以伪造请求。如果不验签,攻击者可以构造假的"支付成功"通知。

错误示例

// ❌ 错误: 直接解密处理,未验签
@PostMapping("/payment/callback/wechat")
public String wechatCallback(@RequestBody String body) {
    JsonNode json = objectMapper.readTree(body);
    // 直接尝试解密 resource
    String decrypted = decryptAesGcm(ciphertext, apiV3Key, nonce, aad);
    processPayment(decrypted);  // 谁发来的都处理
    return "{\"code\":\"SUCCESS\"}";
}

正确做法

// ✅ 正确: 先验签,再解密,再处理
@PostMapping("/payment/callback/wechat")
public String wechatCallback(
    @RequestBody String body,
    @RequestHeader("Wechatpay-Signature") String signature,
    @RequestHeader("Wechatpay-Timestamp") String timestamp,
    @RequestHeader("Wechatpay-Nonce") String nonce,
    @RequestHeader("Wechatpay-Serial") String serial) {

    // 1. 用微信支付平台公钥验签(不是商户私钥)
    String message = timestamp + "\n" + nonce + "\n" + body + "\n";
    PublicKey platformKey = loadPlatformPublicKey(serial);
    if (!verifySignature(message, signature, platformKey)) {
        return "{\"code\":\"FAIL\",\"message\":\"验签失败\"}";
    }

    // 2. 验签通过后再解密和处理
    String decrypted = decryptAesGcm(ciphertext, apiV3Key, nonce, aad);
    processPayment(decrypted);
    return "{\"code\":\"SUCCESS\"}";
}

关键区分

密钥/证书用途持有方
商户私钥商户请求微信时签名商户
商户 API 证书商户身份标识商户
微信支付平台公钥/证书验证微信回调签名微信平台签发,商户持有公钥
API V3 Key解密回调通知体商户

检查清单

  • 回调入口是否在解密前先验证平台签名
  • 验签使用的是平台公钥/证书,而非商户私钥
  • 是否按 Wechatpay-Serial 匹配对应平台证书(支持证书轮换)
  • 验签失败是否直接拒绝,不继续处理

陷阱 #2: 未做防重放校验

场景: 攻击者截获一份真实的支付成功回调,重复发送给系统

问题根因

合法的旧回调报文签名仍然有效,仅靠验签无法防止重放。

错误示例

// ❌ 错误: 验签通过就直接处理,不检查是否重复
if (verifySignature(message, signature, platformKey)) {
    processPayment(decrypted);  // 同一笔单可能被处理多次
}

正确做法

Read the whole SKILL.md on GitHub

More in Engineering