You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中Stripe Webhook签名验证失败问题求助

Stripe Webhook签名验证失败:"Signature not found" 问题排查与解决

核心原因:请求体被修改或读取方式不正确

Stripe的Webhook签名是基于原始请求体的字节流计算的,如果Spring Boot在读取请求体时对内容做了修改(比如编码转换、自动去除空白符、格式化JSON等),就会导致计算出的签名和Stripe发送的签名不一致,触发"Signature not found"或签名不匹配错误。


解决步骤

1. 避免使用@RequestBody直接读取请求体

@RequestBody会自动解析请求体并转换成字符串,这个过程中可能会改变原始字节的编码或格式。正确的做法是读取原始字节流,并且保证请求体只被读取一次(ServletInputStream只能读取一次,所以需要缓存)。

2. 使用ContentCachingRequestWrapper缓存请求体

通过Spring提供的ContentCachingRequestWrapper包装请求,缓存原始字节流,方便后续读取:

  • 先注册一个过滤器:
public class RequestBodyCachingFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        filterChain.doFilter(wrappedRequest, response);
    }
}
  • 在控制器中读取缓存的原始字节:
@PostMapping("/event")
public ResponseEntity<String> processStripeEvents(HttpServletRequest request) {
    String sigHeader = request.getHeader("Stripe-Signature");
    // 从缓存中获取原始请求体字节
    byte[] rawRequestBody = ((ContentCachingRequestWrapper) request).getContentAsByteArray();

    try {
        Event event = Webhook.constructEvent(rawRequestBody, sigHeader, "whsec_your_signing_secret");
        // 处理事件逻辑
        return ResponseEntity.ok("Event processed successfully");
    } catch (SignatureVerificationException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid signature: " + e.getMessage());
    } catch (JsonProcessingException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Invalid event payload");
    }
}

3. 排查Webhook.site的影响

Webhook.site本身不会修改请求体,但要确认:

  • 测试时Stripe控制台的Webhook URL是否指向你的Spring Boot服务,而非Webhook.site。如果之前用Webhook.site测试后没改回自己的服务地址,你的接口根本收不到Stripe的事件,自然会验证失败。
  • 可以用Webhook.site对比Stripe发送的原始请求体和你的服务接收的请求体,看两者是否完全一致(包括换行符、空格、编码等)。

4. 其他关键检查点

  • 确认签名密钥是Stripe控制台中对应Webhook端点的签名密钥(不是API密钥),每个Webhook端点有独立的签名密钥,不要混用。
  • 检查网关/代理(如Nginx)是否修改了请求体或请求头,比如自动压缩、修改Content-Type等,这些都会破坏签名验证。
  • 保证读取请求体时使用UTF-8编码,Stripe发送的请求体默认是UTF-8编码,不要擅自更改编码格式。

内容的提问来源于stack exchange,提问作者suraj bahl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 07:26:01