Shopify HMAC参数验证在Python中失败
我在验证来自Shopify的HMAC参数时遇到一些问题。我根据使用的代码返回了不正确的结果 以下是我的注释代码:Shopify HMAC参数验证在Python中失败,python,shopify,hmac,Python,Shopify,Hmac,我在验证来自Shopify的HMAC参数时遇到一些问题。我根据使用的代码返回了不正确的结果 以下是我的注释代码: import urllib import hmac import hashlib qs = "hmac=96d0a58213b6aa5ca5ef6295023a90694cf21655cf301975978a9aa30e2d3e48&locale=en&protocol=https%3A%2F%2F&shop=myshopname.myshopify.com
import urllib
import hmac
import hashlib
qs = "hmac=96d0a58213b6aa5ca5ef6295023a90694cf21655cf301975978a9aa30e2d3e48&locale=en&protocol=https%3A%2F%2F&shop=myshopname.myshopify.com×tamp=1520883022"
解析查询字符串
params = urllib.parse.parse_qs(qs)
提取hmac值
value = params['hmac'][0]
根据文档从查询字符串中删除参数
del params['hmac']
del params['signature']
重新组合参数
new_qs = urllib.parse.urlencode(params)
计算摘要
h = hmac.new(SECRET.encode("utf8"), msg=new_qs.encode("utf8"), digestmod=hashlib.sha256)
返回False
强>
hmac.compare_digest(h.hexdigest(), value)
从表面上看,这最后一步应该是正确的。这里所遵循的每一步都如Shopify文档中的评论所述。我将发布我自己问题的答案,因为在梳理了Shopify的论坛和其他SO之后,我找不到任何可以明确回答这个问题的内容 最近,Shopify开始在querystring负载中包含
协议
参数。这本身不会是一个问题,除了Shopify在其文档中忽略了一个事实,即在检查签名时,:
和/
不应使用URL编码。这是完全没有意义的,因为他们自己在提供的查询字符串中对这些字符进行URL编码
因此,要解决这个问题,只需为urllib.parse.urlencode
提供safe
参数,其值为:/
(fitting,对吗?)。完整的工作代码如下所示:
params = urllib.parse.parse_qsl(qs)
cleaned_params = []
hmac_value = dict(params)['hmac']
# Sort parameters
for (k, v) in sorted(params):
if k in ['hmac', 'signature']:
continue
cleaned_params.append((k, v))
new_qs = urllib.parse.urlencode(cleaned_params, safe=":/")
secret = SECRET.encode("utf8")
h = hmac.new(secret, msg=new_qs.encode("utf8"), digestmod=hashlib.sha256)
# Compare digests
hmac.compare_digest(h.hexdigest(), hmac_value)
希望这对其他遇到这个问题的人有所帮助
请注意,由于查询参数不是按字典(字母顺序)排序的,因此此代码有点简化。如果可以更清楚地说明这一点,我也可以更新代码来做到这一点。@deliriousoops,那将是一个打字错误。抱歉,我的荣幸,@SamCreamer!可能太晚了,但有人知道“秘密”在哪里(和什么)?我尝试使用“API密钥”,但没有验证(返回False).@lowercase00应该是它;至少这是我的代码库中的内容。@DanLoewenherz最后一行代码中的“值”应该是“hmac_值”@vantrong291感谢您捕捉到这一点,刚刚更新
import hmac
import hashlib
...
# Inside your view in Django's views.py
params = request.GET.dict()
#
myhmac = params.pop('hmac')
params['state'] = int(params['state'])
line = '&'.join([
'%s=%s' % (key, value)
for key, value in sorted(params.items())
])
print(line)
h = hmac.new(
key=SHARED_SECRET.encode('utf-8'),
msg=line.encode('utf-8'),
digestmod=hashlib.sha256
)
# Cinderella ?
print(hmac.compare_digest(h.hexdigest(), myhmac))