Shipwire Webhook签名验证:Rails下HMAC-SHA256校验不匹配问题
Shipwire Webhook签名校验不通过排查指引
核心常见踩坑点
- 签名值拆分遗漏:Shipwire返回的
X-Shipwire-Signature头格式为{HMAC哈希值};secret-id={绑定的密钥ID},直接将整个头字符串作为待比对签名会因分号后附带的元参数导致比对失败,需先按分号拆分,仅取分号前的纯哈希值作为比对目标。 - 请求体被提前修改:使用
request.raw_post计算哈希的逻辑方向正确,但需确认Rails中间件(如Rack::Parser、参数解析器)、反向代理节点是否在请求进入控制器前对原始POST body做了解析、转义或改写,导致本地计算所用的字节流和Shipwire生成签名时使用的原始请求体存在差异。 - 密钥匹配错位:注册Webhook密钥接口返回的
resource.id即为请求头中携带的secret-id,存储密钥时需建立secret-id与对应secret值的映射关系。如果账号下存在多组密钥时固定取用某一组密钥计算,会因密钥与请求头携带的ID不匹配导致校验失败,同时需确认存储的secret为接口返回的完整值,不存在截断、多余空格或换行符的问题。 - 比对方式不规范引入误差:直接用普通字符串相等比较时,可能因缺乏固定时间比对机制引入的时序问题导致校验逻辑误判,需使用框架提供的固定时间比较方法完成比对。
- 签名值拆分遗漏:Shipwire返回的
可直接参考的修正后校验代码
# 拆分请求头携带的签名信息 signature_header = request.headers['X-Shipwire-Signature'] expected_signature, secret_meta = signature_header.split(';') current_secret_id = secret_meta&.split('=')&.last # 根据请求携带的secret-id匹配对应存储的密钥 secret_map = Rails.application.credentials.shipwire[:webhook_secret_mapping] webhook_secret = secret_map[current_secret_id] # 基于未修改的原始请求体计算HMAC-SHA256哈希 raw_body = request.raw_post calculated_hash = OpenSSL::HMAC.hexdigest("sha256", webhook_secret, raw_body) # 使用固定时间比对方法完成校验,避免时序攻击 is_verified = ActiveSupport::SecurityUtils.secure_compare(calculated_hash, expected_signature)
调试技巧:可在日志中输出raw_post的字节长度、拆分后的目标签名值、所用密钥的前后2位字符,逐环节和计算结果对比,快速定位偏差点。
内容的提问来源于stack exchange,提问作者Berimbolo
相关产品推荐
相关产品推荐

