使用散列 "password" 生成 HMAC 签名

Generating HMAC signature with hashed "password"

我正在我的 RESTful API 项目中使用身份验证方法,我非常喜欢生成 HMAC-SHA256 签名作为身份验证方法的想法。

客户正在通过几个简单的步骤创建签名:

# example client-side code
sig = hmac.new(bytes('SUPER_SECRET_KEY', 'utf-8'), b'', sha256)
sig.update(request_path)
sig.update(request_body)
# ...other variables needed for generating the signature...

signature = sig.hexdigest()

并将其添加到请求 header 以及他的 "user name"(例如 Authorization: THE_USER_NAME:abcd1234xyz890)。

在 server-side 上,我正在尝试以同样的方式 re-create 它:

# example server-side code
def do_check(request):
    # get user name from request header
    username = request.headers['Authorization'].split(':')[0]

    # some method to retrieve the "secret key" from database
    user = db.User().filter(username=username).one()

    # use user's "secret key" to generate the signature
    sig = hmac.new(bytes(user.key, 'utf8'), b'', sha256)
    sig.update(bytes(request.path, 'utf-8'))
    sig.update(request.data)
    # ...other variables needed for generating the signature...

    return sig.hexdigest()
    # compare the returned signature with the one client sent us...

只要我将用户的密钥作为 纯文本 存储在我的数据库中,所有这些都可以正常工作:

| username      | key              |
------------------------------------
| THE_USER_NAME | SUPER_SECRET_KEY |

我们都知道这是 绝对不能接受的 ,所以我尝试简单地用 bcrypt 散列 SUPER_SECRET_KEY 并存储散列字符串:

| username      | key                                                          |
--------------------------------------------------------------------------------
| THE_USER_NAME | b$UOIKEBFBedbcYFhbXBclJOZIEgSGaFmeZYhQtaE4l6WobFW1qvIf6 |

我现在面临的问题是客户端使用了 "secret key" 的 un-hashed 版本来生成我无法在 server-side 上执行的签名,因为我没有它在 plain-text 了。

类似方法的示例之一是 generating HMAC signature in Amazon Web Services (also simplified explanation of the same process),它不需要任何额外的 log-ins 或身份验证,也不会为 [=46] 提供任何令牌或 "replacements" =]组合。我真的怀疑 AWS 是否将秘密以纯文本形式存储在数据库中 (?)

如何在 server-side 上使用数据库中 "secret key" 的散列版本重新创建 HMAC 签名,同时不强制 client-side 更改其签名生成方法(例如避免安装bcrypt 甚至完全散列秘密)?

密码散列不使用共享密钥。散列秘密的行为应该会破坏实际值,同时保留验证密码的能力。不能合理地期望您从哈希中恢复密码。

Hmac 身份验证和验证使用共享密钥。双方都必须知道这个秘密。

因此,密码散列与 hmac 根本不同,您不能简单地对 hmac 密钥进行散列。哈希将不允许您返回到实际密钥。

[澄清后删除无关部分]

所以你必须在某个地方有某种秘密,但它不需要在数据库中。实际的 hmac 共享机密可以使用对称密码在数据库中加密(使用不在数据库中的不同密钥)。因此,服务器读取加密的 hmac 密钥,对其进行解密并使用它。

重要的是你必须以某种你可以解密的方式对其进行加密,这排除了散列。