Python 中的 Shopify HMAC 参数验证失败
Shopify HMAC parameter verification failing in Python
我在验证来自 Shopify 的 HMAC 参数时遇到了一些问题。我根据 Shopify documentation 使用的代码是 return 一个不正确的结果。
这是我的注释代码:
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)
Returns False
!
hmac.compare_digest(h.hexdigest(), value)
从表面上看,最后一步应该 return 正确。此处遵循的每个步骤都在 Shopify 文档中进行了概述。
我要 post 回答我自己的问题,因为在梳理了 Shopify 的论坛和 SO 的其余部分之后,我找不到任何可以明确回答这个问题的东西。
最近,Shopify 开始在查询字符串负载中包含 protocol
参数。这本身不是问题, 除了 因为 Shopify 在他们的文档中忽略了提到 :
和 /
不是 [=33] =] 检查签名时。这是完全荒谬的,因为他们自己 do URL-encode 他们提供的查询字符串中的这些字符。
因此,要解决此问题,只需将 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(), hmac_value)
希望这对其他运行进入这个问题的人有所帮助!
请注意,此代码有些简化,因为查询参数未按字典顺序(字母顺序)排序。如果这可以更清楚,我也可以更新代码来做到这一点。
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))
我在验证来自 Shopify 的 HMAC 参数时遇到了一些问题。我根据 Shopify documentation 使用的代码是 return 一个不正确的结果。
这是我的注释代码:
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)
Returns False
!
hmac.compare_digest(h.hexdigest(), value)
从表面上看,最后一步应该 return 正确。此处遵循的每个步骤都在 Shopify 文档中进行了概述。
我要 post 回答我自己的问题,因为在梳理了 Shopify 的论坛和 SO 的其余部分之后,我找不到任何可以明确回答这个问题的东西。
最近,Shopify 开始在查询字符串负载中包含 protocol
参数。这本身不是问题, 除了 因为 Shopify 在他们的文档中忽略了提到 :
和 /
不是 [=33] =] 检查签名时。这是完全荒谬的,因为他们自己 do URL-encode 他们提供的查询字符串中的这些字符。
因此,要解决此问题,只需将 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(), hmac_value)
希望这对其他运行进入这个问题的人有所帮助!
请注意,此代码有些简化,因为查询参数未按字典顺序(字母顺序)排序。如果这可以更清楚,我也可以更新代码来做到这一点。
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))