python - 为什么 Stripe-Signature header 永远不会匹配 request.body 的签名?

标签 python django django-rest-framework stripe-payments

我将 Python 与 Django Rest 框架结合使用,并尝试从 stripe 正确接收 webhook 事件。

但是我经常遇到这个错误:

stripe.error.SignatureVerificationError: No signatures found matching the expected signature for payload

这是代码:

WEBHOOK_SECRET = settings.STRIPE_WEBHOOK_SK

@csrf_exempt
def webhook(request):
    sig_header = request.headers.get('Stripe-Signature', None)
    payload = request.body
    try:
        event = stripe.Webhook.construct_event(
            payload=payload, 
            sig_header=sig_header, 
            secret=WEBHOOK_SECRET
        )
    except ValueError as e:
        raise e
    except stripe.error.SignatureVerificationError as e:
        raise e

    return HttpResponse(status=200)

我也试过像这样修改请求正文格式:

payload = request.body.decode('utf-8')
# and also
payload = json.loads(request.body)

但没有运气。

错误来自 WebhookSignature 类中的 verify_header() 类方法。

这是方法失败的部分:

if not any(util.secure_compare(expected_sig, s) for s in signatures):
    raise error.SignatureVerificationError(
        "No signatures found matching the expected signature for payload",
        header,
        payload,
    )

所以我在这一行之前打印了exptected_sigsignatures,发现不管request.body是什么格式, signatures 始终存在(这很好),但它们与 header 中的签名不匹配。

这是为什么?

最佳答案

当 Stripe 计算它发送给您的事件的签名时,它使用代表整个事件内容的特定“有效负载”。签名是在那个确切的有效负载上完成的,对其进行的任何更改(例如添加新行、删除空格或更改属性的顺序)都会更改有效负载和相应的签名。

当您验证签名时,您需要确保您传递的是 Stripe 发送给您的准确原始负载,否则您计算出的签名将与 Stripe 签名不匹配。

框架有时会尝试在收到请求时提供帮助,它们会检测 JSON 并自动为您解析它。这意味着您认为您获得的是“原始有效负载/正文”,但实际上您获得的是替代版本。它具有相同的内容,但与 Stripe 发送给您的内容不匹配。

例如,这在 Node.js 中的 Express 中很常见。因此,作为开发人员,您必须明确请求 Stripe 发送给您的确切原始/原始负载。以及如何做到这一点可能因多种因素而异。 strip 节点 github 上有 2 个问题,有许多潜在的修复 herehere .

对于 Django,同样的情况也会发生,您需要确保您的代码请求原始负载。您似乎按预期使用了 request.body,但这是您想要进一步深入研究的一件事。

此外,另一个常见错误是使用了错误的 Webhook 密码。例如,如果您使用 Stripe CLI,它会为您创建一个 key ,该 key 与您在仪表板中看到的此 Webhook 端点的 key 不同。您需要确保根据您所处的环境使用正确的 key 。

关于python - 为什么 Stripe-Signature header 永远不会匹配 request.body 的签名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72115626/

相关文章:

python - 神经网络用一个神经元预测不良

python - Django 重命名模型。创建新的 django_content_type 而不是重命名旧记录

python - 在pygame中的透明表面上渲染抗锯齿文本

css - Django 表单自定义

python - Django:搜索短语中单个单词的首字母?

python - 使用 south 重命名 django 模型类名和相应的外键,而不会丢失数据

javascript - 如何用Django REST Framework实现实时更新?

python - 如何使用从登录 View 获得的 jwt token 进行身份验证

python - 在python上导入Librosa时出错

mysql - 使用带有连接表的 Django-Rest-Framework 创建 API