gpt4 book ai didi

php - 在 Python 中使用 flask 进行 Hmac 验证(在 PHP 和 RUBY 中有引用)

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:40:18 24 4
gpt4 key购买 nike

我一直在研究一种在 python 中使用 flask 为 selly.gg 商家网站实现 HMAC 验证的方法。

因此 selly 的开发文档提供了以下示例来验证 HMAC 签名(在 PHP 和 ruby​​ 中):https://developer.selly.gg/?php#signing-validating(代码如下:)

PHP:

<?php
$signature = hash_hmac('sha512', json_encode($_POST), $secret);
if hash_equals($signature, $signatureFromHeader) {
// Webhook is valid
}
?>

ruby :

signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), secret, payload.to_json)
is_valid_signature = ActiveSupport::SecurityUtils.secure_compare(request.headers['X-Selly-Signature'], signature)

所以,到目前为止我能弄清楚的是:他们不使用 base64 编码(就像 shopify 和其他人那样),它使用 SHA-512,它将密码与 json 响应数据一起编码,最后请求 header 是 ' X-Selly-签名'

到目前为止,我已经编写了以下代码(基于 shopify 的 HMAC 签名代码 https://help.shopify.com/en/api/getting-started/webhooks ):

SECRET = "secretkeyhere"
def verify_webhook(data, hmac_header):
digest = hmac.new(bytes(SECRET, 'ascii'), bytes(json.dumps(data), 'utf8'), hashlib.sha512).hexdigest()
return hmac.compare_digest(digest, hmac_header)
try:
responsebody = request.json #line:22
status = responsebody['status']#line:25
except Exception as e:
print(e)
return not_found()
print("X Selly sign: " + request.headers.get('X-Selly-Signature'))
verified = verify_webhook(responsebody, request.headers.get('X-Selly-Signature'))
print(verified)

但是 selly 有一个 webhook 模拟器,即使有正确的 key 和有效请求,verify_webhook 也总是返回 False。我尝试联系 Selly 支持,但他们帮不上忙

您可以在以下地址测试webhook模拟器: https://selly.io/dashboard/{your account}/developer/webhook/模拟

最佳答案

除了您不需要 json.dumps 请求数据外,您几乎是对的。这可能会在输出中引入更改,例如格式更改,这将与原始数据不匹配,这意味着 HMAC 将失败。

例如

{"id":"fd87d909-fbfc-466c-964a-5478d5bc066a"}

不同于:

{
"id":"fd87d909-fbfc-466c-964a-5478d5bc066a"
}

实际上是:

{x0ax20x20"id":"fd87d909-fbfc-466c-964a-5478d5bc066a"x0a}

两个输入的哈希将完全不同。

查看 json.loadsjson.dumps 将如何修改格式以及哈希:

http_data = b'''{
"id":"fd87d909-fbfc-466c-964a-5478d5bc066a"
}
'''
print(http_data)
h = hashlib.sha512(http_data).hexdigest()
print(h)
py_dict = json.loads(http_data) # deserialise to Python dict
py_str = json.dumps(py_dict) # serialise to a Python str
py_bytes = json.dumps(py_dict).encode('utf-8') # encode to UTF-8 bytes
print(py_str)
h2 = hashlib.sha512(py_bytes).hexdigest()
print(h2)

输出:

b'{\n    "id":"fd87d909-fbfc-466c-964a-5478d5bc066a"\n}\n'
364325098....
{"id": "fd87d909-fbfc-466c-964a-5478d5bc066a"}
9664f687a....

Selly 的 PHP 示例显示了类似的内容,这无济于事。事实上,Selly PHP 示例是无用的,因为无论如何数据都不会进行形式编码,因此数据不会在 $_POST 中!

这是我的 Flask 小例子:

import hmac
import hashlib
from flask import Flask, request, Response

app = Flask(__name__)

php_hash = "01e5335ed340ef3f211903f6c8b0e4ae34c585664da51066137a2a8aa02c2b90ca13da28622aa3948b9734eff65b13a099dd69f49203bc2d7ae60ebee9f5d858"
secret = "1234ABC".encode("ascii") # returns a byte object

@app.route("/", methods=['POST', 'GET'])
def selly():
request_data = request.data # returns a byte object
hm = hmac.new(secret, request_data, hashlib.sha512)
sig = hm.hexdigest()

resp = f"""req: {request_data}
sig: {sig}
match: {sig==php_hash}"""

return Response(resp, mimetype='text/plain')

app.run(debug=True)

注意使用 request.data 获取原始字节输入,并在 secret str 上简单使用 encode 获取编码字节(而不是使用冗长的 bytes() 实例化)。

这可以通过以下方式进行测试:

curl -X "POST" "http://localhost:5000/" \
-H 'Content-Type: text/plain; charset=utf-8' \
-d "{\"id\":\"fd87d909-fbfc-466c-964a-5478d5bc066a\"}"

我还创建了一些 PHP 来验证两种语言创建相同的结果:

<?php
header('Content-Type: text/plain');
$post = file_get_contents('php://input');
print $post;
$signature = hash_hmac('sha512', $post, "1234ABC");
print $signature;
?>

关于php - 在 Python 中使用 flask 进行 Hmac 验证(在 PHP 和 RUBY 中有引用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56727357/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com