【问题标题】:python - hmac new sha1python - hmac 新的 sha1
【发布时间】:2019-08-17 16:48:58
【问题描述】:

我试图得到与this online API service produces 相同的结果。

通过输入 key 作为应用程序密钥,并输入 secret 作为秘密,生成以下 URL:

http://webservices.esd.org.uk/organisations/barrowbc?ApplicationKey=key&Signature=YXWJsGSKnLcENW1vm30EYObbCsA=

我尝试使用以下代码生成相同的签名:

import hmac    
import urllib
import base64
from hashlib import sha1


def sign_url(url,key,secret):
    url = url + 'ApplicationKey=' + key
    signature = hmac.new(secret,url,sha1).digest().encode("base64") 
    signature = '&Signature=' + signature
    url = url + signature
    print(url)

sign_url('http://webservices.esd.org.uk/organisations/barrowbc','key','secret')

但这会产生:

http://webservices.esd.org.uk/organisations/barrowbcApplicationKey=key&Signature=W//jgV+xdSbTBG6+i1TCGN/Kbsk=

预期的签名是

YXWJsGSKnLcENW1vm30EYObbCsA=

但我的代码输出

W//jgV+xdSbTBG6+i1TCGN/Kbsk=

【问题讨论】:

  • 是否有任何关于签名必须基于哪些输入的文档?
  • 有这个:api.esd.org.uk/pythoncode.txt,该网站在这里建议:api.esd.org.uk/security
  • 坦率地说,他们的文档非常糟糕,而且 Python 代码几乎不完整。请注意,它们的 URL 以 ? 结尾,并且不考虑其他查询参数。它也不处理 URL 编码。我查看了他们的 PHP 代码并确认他们需要使用 URL 编码 decoded 对 URL 进行哈希处理。

标签: python python-2.7 sha1 hmac


【解决方案1】:

您的版本在Application= 参数之前缺少必需的? 组件。但是,如果还有其他参数,您可能想要添加 &,并且您需要删除 .encode("base64") 添加到值末尾的换行符:

def sign_url(url, key, secret):
    sep = '&' if '?' in url else '?'
    url = '{}{}ApplicationKey={}'.format(url, sep, key)
    signature = hmac.new(secret, url, sha1).digest().encode("base64") 
    return '{}&Signature={}'.format(url, signature[:-1])

我注意到,当 URL 包含 URL 编码元素 时,签名似乎应用于 URL 解码版本(+ 解释为空格),所以你真的想要签名时添加urllib.unquote_plus() (Python 2) / urllib.parse.unquote_plus() (Python 3) 调用:

try:
    from urllib.parse import unquote_plus
except ImportError:
    from urlib import unquote_plus

def sign_url(url, key, secret):
    sep = '&' if '?' in url else '?'
    url = '{}{}ApplicationKey={}'.format(url, sep, key)
    signature = hmac.new(secret, unquote_plus(url), sha1).digest().encode("base64") 
    return '{}&Signature={}'.format(url, signature[:-1])

我已经确认这是他们的PHP example code 所做的,并验证了online signature tool 中的示例查询参数,例如在工具中输入路径和参数foo%20bar?foo%20bar 时,会生成CCuMYpCDznH4vIv95+NrN+RHEK0= 作为签名,但使用foo+bar?foo+bar 会生成完全相同的签名,即使+ should only be decoded as a space in form data 也是如此。

我会解析出 URL,将 ApplicationKey 参数添加到解析的参数中,然后构造一个新的 URL 进行签名。

这是一个可以做到这一点的版本,并且可以在 Python 2 和 Python 3 上运行:

import hmac
import base64
from hashlib import sha1

try:
    # Python 3
    from urllib.parse import parse_qsl, unquote_plus, urlencode, urlparse
except ImportError:
    # Python 2
    from urlparse import urlparse, parse_qsl
    from urllib import unquote_plus, urlencode

def sign_url(url, key, secret):
    parsed = urlparse(url)
    query = parse_qsl(parsed.query)
    query.append(('ApplicationKey', key))
    to_sign = unquote_plus(parsed._replace(query=urlencode(query)).geturl())

    if not isinstance(secret, bytes):
        secret = secret.encode()
    if not isinstance(to_sign, bytes):
        to_sign = to_sign.encode()
    signature = base64.b64encode(hmac.new(secret, to_sign, sha1).digest())
    if not isinstance(signature, str):
        signature = signature.decode()

    query.append(('Signature', signature))
    return parsed._replace(query=urlencode(query)).geturl()

【讨论】:

    猜你喜欢
    • 2012-10-12
    • 1970-01-01
    • 1970-01-01
    • 2012-01-10
    • 2011-01-28
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 2011-11-09
    相关资源
    最近更新 更多