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

Ela*_*lad 30 security encryption password-protection hmac

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

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

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

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

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

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

caf*_*caf 34

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

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

以可逆格式存储密码是不好的,因为如果您的数据库被泄露,那么攻击者已经获得了可能(并且可能已经)在其他地方使用过的密码.另一方面,存储共享密钥并不是一个问题 - 这是您的服务所特有的秘密,因此所有攻击者都获得了登录您服务的能力.

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

  • 您描述的非对称系统是一个很好的方案!但是有一个权衡(总有,不存在吗?).问题是现在必须协调客户端和服务器.这是一个潘多拉的一堆奇怪的错误,没有人能理解,直到你意识到它们已经失序.它还会产生并发问题(例如,如果客户端应用程序有多个实例访问API).简而言之,为了安全起见,它增加了很多复杂性. (6认同)

roo*_*ook 11

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

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

  • @Elad由于用户名和密码是一种状态,因此可以说你不能成为真正的无状态并具有身份验证.当然,每个经过身份验证的REST实现都会为了安全起见而做出这种妥协. (5认同)