Shopify HMAC参数验证在Python中失败

时间:2018-03-12 20:48:31

标签: python shopify hmac

我在验证来自Shopify的HMAC参数时遇到了一些麻烦。我根据Shopify documentation使用的代码返回的结果不正确。

这是我带注释的代码:

import urllib
import hmac
import hashlib

qs = "hmac=96d0a58213b6aa5ca5ef6295023a90694cf21655cf301975978a9aa30e2d3e48&locale=en&protocol=https%3A%2F%2F&shop=myshopname.myshopify.com&timestamp=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文档中进行了评论。

2 个答案:

答案 0 :(得分:2)

我将回答我自己的问题,因为在通过Shopify的论坛和SO的其余部分进行梳理之后,我找不到任何能够明确回答这个问题的答案。

最近,Shopify开始在查询字符串有效负载中包含protocol参数。这本身不会有问题,之外,因为Shopify在文档中忽略了:/在检查时不进行URL编码的事实签名。这是完全没有意义的,因为他们自己在他们提供的查询字符串中对这些字符进行URL编码。

因此,要解决此问题,只需将safe参数提供给urllib.parse.urlencode,其值为:/(拟合,对吗?)。完整的工作代码如下所示:

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(), value)

希望这对遇到此问题的其他人有帮助!

请注意,此代码有些简化,因为查询参数不按字典顺序(按字母顺序)排序。如果这可以更清楚,我也可以更新代码来执行此操作。

答案 1 :(得分:0)

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))