我正在设计REST API,在验证用户的安全性方面存在一些问题。 对于身份验证,我不希望密码以纯文本形式通过网络发送。
要绕过此问题,我可以发送密码的SHA-256哈希值(用户名为salt),因此密码永远不会以纯文本形式发送。在我的数据库中,我将存储以下哈希:SHA256(密码+盐),如果两个哈希匹配,我将进行比较。
这个选项的问题在于我将使用快速哈希算法计算哈希,并且盐不是随机的。
在安全性方面,最佳做法是使用慢速签名算法,使用随机盐(如bcrypt)。
慢速算法不是问题,我可以在客户端使用bcrypt,但对于salt我不知道该怎么做:
所以我可以看到3个选项,但没有一个是令人满意的:
有人有更好的解决方案或一些建议吗?
答案 0 :(得分:2)
客户端散列方法有几个优点。其中之一是服务器永远不会获得真正的密码,因此如果服务器以任何方式受到损害,它仍然无法获得真正的密码。另一个是,如果你打算使用慢速哈希,它可以减轻服务器端的负担。
但是,散列密码旨在保护您,以防数据库被破坏并且哈希被盗。这意味着如果有人获得了哈希密码,他们仍然可以通过发送哈希模拟用户。这意味着,即使您在客户端进行哈希,您仍需要在服务器上重新哈希。
另一个潜在的缺点是,这可能会疏远未启用JavaScript的部分用户群。
解决您的观点:
Bcrypt需要一个定义大小的盐,所以我不能把用户名
不要将用户名用作盐。盐应该是唯一的,用户名(及其派生词)肯定不是唯一的。独一无二的我并不仅仅意味着服务器的独特之处,而是无处不在。请使用加密随机数。
如果我使用随机盐,客户端在计算密码的哈希值之前如何知道这个盐的值?
让服务器事先发送salt(nonce)。您也可以在客户端上执行此操作,但据我所知,Javascript没有CSPRNG,您仍然需要将该随机数发送回服务器。
我以纯文本发送密码(我正在使用SSL)并且我将bcrypt存储在db =>中仍然容易受到中间人的影响
SSL旨在防止中间人攻击。除非它以某种方式被打破,否则这不会成为问题。
我使用SHA256并发送哈希,其中salt是用户名(仍使用SSL)=> db中的哈希值不太安全
不要将用户名用作盐。就像我之前说的那样,无论你是否在客户端做到这一点,你都必须在服务器端进行哈希。
我使用bcrypt并且我有两个步骤:我为给定用户请求salt然后发送该用户的哈希值(仍然使用ssl)=>通过尝试使用其他用户名登录,我可以获得他的盐,而不是很棒
确实不太棒。
答案 1 :(得分:1)
我认为你可能会在这里混淆/混淆一些问题:
希望这有帮助!
答案 2 :(得分:1)
hash_val = HASH(HASH('username') + 'password')
存储在服务器端。nonce = HASH(RAND())
client_hash = HASH( nonce + HASH(HASH('username') + 'password'))
计算以下内容并将其发送回服务器。通过这种方式,通过网络发送的哈希只使用一次,并且您可以免受“重播”和MITM攻击。
另外,查看PBKDF之类的东西来存储密码而不仅仅是哈希,它使得强制执行和彩虹表都完全不切实际。 Here's the PHP implementation I'm using since it's not in PHP yet
答案 3 :(得分:0)
如果可能,使用API创建API密钥和密钥(API用户名/密码,显然每个用户都是唯一的)。您应该在站点界面中提供一个选项来激活/取消激活API访问,以及重新生成API密钥和密钥的选项。在这个界面上,用户将看到API的API /密钥。