我应该使用HMAC摘要的Base64还是仅使用HMAC十六进制摘要? [英] Should I use Base64 of HMAC digest or just HMAC hex digest?

查看:114
本文介绍了我应该使用HMAC摘要的Base64还是仅使用HMAC十六进制摘要?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

传奇

我公开了一个API,该API要求客户端通过发送两个标头来签署请求:

I expose an API which requires client to sign requests by sending two headers:

Authorization: MyCompany access_key:<signature>
Unix-TimeStamp: <unix utc timestamp in seconds>

要创建签名部分,客户端应使用我的API服务发布的密钥。

To create a signature part, the client should use a secret key issued by my API service.

在Python(Py3k)中可能看起来像这样:

In Python (Py3k) it could look like:

import base64
import hmac
from hashlib import sha256
from datetime import datetime

UTF8 = 'utf-8'
AUTH_HEADER_PREFIX = 'MyCompany'

def create_signature(access_key, secret_key, message):
    new_hmac = hmac.new(bytes(secret_key, UTF8), digestmod=sha256)
    new_hmac.update(bytes(message, UTF8))
    signature_base64 = base64.b64encode(new_hmac.digest())
    return '{prefix} {access_key}:{signature}'.format(
        prefix=AUTH_HEADER_PREFIX,
        access_key=access_key,
        signature=str(signature_base64, UTF8).strip()
    )


if __name__ == '__main__':
    message = str(datetime.utcnow().timestamp())
    signature = create_signature('my access key', 'my secret key',  message)
    print(
        'Request headers are',
        'Authorization: {}'.format(signature),
        'Unix-Timestamp: {}'.format(message),
        sep='\n'
    )
    # For message='1457369891.672671', 
    # access_key='my access key' 
    # and secret_key='my secret key' will ouput:
    #
    # Request headers are
    # Authorization: MyCompany my access key:CUfIjOFtB43eSire0f5GJ2Q6N4dX3Mw0KMGVaf6plUI=
    # Unix-Timestamp: 1457369891.672671

我想知道是否可以避免将字节摘要编码为Base64,而只使用 HMAC.hexdigest() 来检索串。
这样我的函数将更改为:

I wondered if I could avoid dealing with encoding digest of bytes to Base64 and just use HMAC.hexdigest() to retrieve a string. So that my function will change to:

def create_signature(access_key, secret_key, message):
    new_hmac = hmac.new(bytes(secret_key, UTF8), digestmod=sha256)
    new_hmac.update(bytes(message, UTF8))
    signature = new_hmac.hexdigest()
    return '{prefix} {access_key}:{signature}'.format(
        prefix=AUTH_HEADER_PREFIX,
        access_key=access_key,
        signature=signature
    )

但是后来我发现 Amazon使用与我的第一个代码段类似的方法

Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature;

Signature = Base64( HMAC-SHA1( YourSecretAccessKeyID, UTF-8-Encoding-Of( StringToSign ) ) );

看到亚马逊不使用十六进制摘要,我停止了前进,因为也许他们知道

Seeing that Amazon doesn't use hex digest I stopped myself to move forward with it because maybe they know something I don't.

更新

我测量了性能,发现十六进制摘要更快:

I've measured a performance and found hex digest to be faster:

import base64
import hmac
import string
from hashlib import sha256


UTF8 = 'utf-8'
MESSAGE = '1457369891.672671'
SECRET_KEY = 'my secret key'
NEW_HMAC = create_hmac()


def create_hmac():
    new_hmac = hmac.new(bytes(SECRET_KEY, UTF8), digestmod=sha256)
    new_hmac.update(bytes(MESSAGE, UTF8))
    return new_hmac


def base64_digest():
    return base64.b64encode(NEW_HMAC.digest())


def hex_digest():
    return NEW_HMAC.hexdigest()



if __name__ == '__main__':
    from timeit import timeit

    print(timeit('base64_digest()', number=1000000,
                  setup='from __main__ import base64_digest'))
    print(timeit('hex_digest()', number=1000000,
                 setup='from __main__ import hex_digest'))

结果为:

3.136568891000934
2.3460130329913227






问题#1

有人知道为什么他们坚持使用Base64字节摘要并且不仅仅使用十六进制摘要?是否有确凿的理由在十六进制摘要中继续使用此方法?

Does someone know why do they stick to Base64 of bytes digest and don't use just hex digest? Is there some solid reason to keep using this approach over hex digest?

问题#2

根据 RFC2716 授权的格式使用基本身份验证
时的标头值为:

According to RFC2716 the format of Authorization header value when using Basic Authentication is:

Authorization: Base64(username:password)

因此,基本上,您用Base64包装了两个用冒号分隔的值(用户ID和密码)。

So basically you wrap with Base64 two values (user's id and password) seprated by colon.

正如您在我的代码段和Amazon文档中所看到的那样,我也不是,Amazon也没有为 Authorization 标头。
将整个对包裹为 Base64(access_key:signature)会更接近于此RFC,还是更好的样式吗?

As you can see in my code snippet and in Amazon's documentation nor me, nor Amazon do that for own custom value of the Authorization header. Would it be a better style to wrap the whole pair as Base64(access_key:signature) to stick closer to this RFC or it doesn't matter at all?

推荐答案

Amazon 使用在签名版本4中使用十六进制摘要。

Amazon does use the hex digest in Signature Version 4.


授权:A​​WS4-HMAC-SHA256凭证= AKIDEXAMPLE / 20150830 / us-east-1 / iam / aws4_request,SignedHeaders =内容类型; host; x-amz-date,Signature = 5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7

http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to -request.html

您的示例来自签名版本2,后者是较旧的算法,它使用Base-64编码签名(而且最新的AWS区域也不支持)。

Your example is from Signature Version 2, the older algorithm, which does use Base-64 encoding for the signature (and which also is not supported in the newest AWS regions).

因此,知道AWS知道您不会放错东西,因为他们的较新算法使用了它。

So, your concern that AWS knows something you don't is misplaced, since their newer algorithm uses it.

授权中:标头,除了几个额外的八位字节外,它实际上没有任何区别。

In the Authorization: header, it really doesn't make a difference other than a few extra octets.

在查询字符串中传递签名时,Base-64会变得混乱,因为 + 和(取决于关于您问谁) / = 需要特殊处理-它们需要转义网址(编码)为%2B %2F %3D ...或者您必须为服务器上可能的变化而做出调整...或者您必须要求使用非标准的Base-64字母,其中 + / = 变为- _ CloudFront的方式。 (此特定的非标准字母只是多个非标准选项中的一个,它们全部解决 Base-64 URL中的魔术字符问题)。

Where Base-64 gets messy is when the signature is passed in the query string, because + and (depending on who you ask) / and = require special handling -- they need to be url-escaped ("percent-encoded") as %2B, %2F, and %3D respectively... or you have to make accommodations for the possible variations on the server... or you have to require the use of a non-standard Base-64 alphabet, where + / = becomes - ~ _ the way CloudFront does it. (This particular non-standard alphabet is only one of multiple non-standard options, all "solving" the same problem of magic characters in URLs with Base-64).

进行十六进制编码。

您几乎不可避免地会发现想要使用Base-64的API难以使用的API使用者。

You will almost inevitably find would-be consumers of your API that find Base-64 to be "difficult."

这篇关于我应该使用HMAC摘要的Base64还是仅使用HMAC十六进制摘要?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆