使用HMAC-SHA1进行API身份验证 - 如何安全地存储客户端密码?

时间:2011-03-30 14:33:11

标签: security encryption password-protection hmac

在使用S3-style身份验证的RESTful API中,API客户端使用HMAC-SHA1使用其密钥对请求进行签名,因此密钥永远不会通过线路传输。 然后,服务器使用该客户端的密钥对客户端进行身份验证,以重复签名过程本身,并将结果与​​客户端发送的签名进行比较。

这一切都很好,但这意味着服务器需要访问客户端共享密钥的明文。面对所有建议,这反对在数据库中清除用户密码。就我所知,只存储密码的盐渍哈希不是一个选项 - 因为那时我无法验证客户的签名。

我应该强调我的API是RESTful的,因此应该是无状态的:我宁愿在其他API调用之前避免登录步骤。

一种可选的解决方案是使用一些对称密钥算法加密所有用户密码。但是,服务器必须将密钥存储在易于访问的的某个加密位置,例如,在源代码中。这比没有好,但不是最佳解决方案(正如@Rook在他的回答中提到的,它违反了CWE-257)。

解决方案的另一个方向可能是不对称签名,但我无法弄清楚如何将其应用于HMAC,并且找不到关于该主题的任何文章。

我错过了一些明显的东西吗?许多可敬的提供商已经实施了这种认证方案 - 它们不能都违反共同的安全原则,是吗? 如果没有,您是否有可以分享的最佳实践?

3 个答案:

答案 0 :(得分:34)

这是对称密钥质询 - 响应式身份验证的缺点 - 您不会将密码置于线路上,但您必须在两端存储密钥。 (HMAC是对称密钥系统)。

请注意,它不是密码 - 它是共享密钥。这里存在根本区别 - 密码通常由用户选择,而共享密钥随机生成并提供给用户(在此上下文中,它们通常称为“API密钥”)。

以可逆格式存储密码很糟糕,因为如果您的数据库遭到入侵,那么攻击者就已经获得了可能(可能已经)在其他地方使用过的密码。另一方面,存储共享秘密不是一个问题 - 它是特定于您的服务的秘密,因此所有攻击者都获得了登录您服务的能力。

另一方面, 可能具有非对称系统,不必在服务器端存储秘密。基本思想是服务器知道客户端的公钥和当前消息序列号。当发送API请求时,客户端递增消息序列号并计算序列号和API请求参数上的签名,服务器可以使用公钥来验证。如果消息包含旧消息序列号,则服务器拒绝该消息,以防止重放攻击。

答案 1 :(得分:11)

理想情况下,在用户登录后,您可以为其提供一个加密随机数,该加密随机数用作该会话生命周期的HMAC密钥K.这是一种安全的方法,但它不是RESTful,因为REST是无状态的。每次登录发出的消息认证代码的概念在技术上是一种状态。

加密密码并将其存储在数据库中违反了CWE-257

答案 2 :(得分:2)

我不确定我是否遗漏了一些东西,但有一个选项是使用散列密码作为对称密钥。