当用户在我的网站上注册时,我想将他们的用户名和哈希密码存储在我的数据库中。当我散列该密码时,我将使用 PHP 对其进行加盐。
问题是,我不想将盐存储在可能被破坏的数据库中——这违背了加盐的目的,不是吗?
相反,我希望每个用户都有一个唯一的盐,存储在单独的服务器上 - 例如,云平台?
这是安全/正确的方式吗?
当用户在我的网站上注册时,我想将他们的用户名和哈希密码存储在我的数据库中。当我散列该密码时,我将使用 PHP 对其进行加盐。
问题是,我不想将盐存储在可能被破坏的数据库中——这违背了加盐的目的,不是吗?
相反,我希望每个用户都有一个唯一的盐,存储在单独的服务器上 - 例如,云平台?
这是安全/正确的方式吗?
如果攻击者学习了盐,这不是问题。盐并不意味着保密。对于盐来说,重要的是它对于每个散列密码实例都是唯一的(即不仅每个用户唯一的盐,而且当用户更改他的密码时必须更改用户的盐)。
如果您认为您的盐可以在密码之间共享,但攻击者不得知道,那么这不是盐;这是一个关键。在密码散列的情况下,有些人将此类密钥称为“胡椒”。这是一个与盐完全不同的概念,一般来说,它增加了复杂性并增加了故障频率,而没有真正提高安全性。首先正确掌握基础知识(即使用正确的函数和适当的盐)。
正常的方法是将盐与哈希值一起存储。最好让密码散列库生成盐,并将盐和散列值的编码作为单个字符串处理。因此,请确保使用 PHP 5.5(或更新版本),并使用password_hash()(并且不要使用手动 salt 设置;默认情况下,该库会做正确的事情,所以就让它去做吧)。在可能的密码散列函数中,bcrypt 是你现在可以拥有的最好的,这就是password_hash()将要使用的。
我的答案会与其他人不同。Tom Leek 和 Xander 提供了很好的见解,所以我对你最初的问题的回答是,从你的评论中扩展而来:
“我不想将盐存储在可能被破坏的数据库中——这违背了加盐的目的,不是吗? ”
是的,没有。如果有人破坏了您的数据库,您需要担心更大的事情。仅仅因为他们做到了这一点,就有可能在网络上进行嗅探,如果不使用加密,数据在被加密并推送到数据库之前是可见的。
盐可以起到保护作用,因为它们增加了一层来防止开裂。破解者需要对密码和盐进行散列,以产生与已知散列进行比较以找到正确密码的内容。大多数盐渍变化,否则如果发生这种情况,盐渍将无用:
User1 (password) [ kitten + your_static_salt = thundercat ]
User2 (password) [ kitten + your_static_salt = thundercat ]
在上面的剧情中,两个用户选择了“kitten”这个词作为他们的密码,该密码被加盐以产生“thundercat”的结果。如果这是真的,腌制部分有点没用。如果您使用 PHP 中的 password_hash,盐会为您随机生成,结果将如下(为了清晰起见,当然会最小化):
User1 (password) [ kitten + password_hash = thundercat ]
User2 (password) [ kitten + password_hash = uppercut ]
在上面,我们看到相同的密码,PHP 的 password_hash 每次都会更改 salt。无需在这里重新发明任何轮子,因为您需要深入了解 crypt() 才能理解它。如果您真的很关心加盐和密码安全,请查看Solar Designer 的 phpass,但是当您声明您担心有人损害数据库本身时,这会改变攻击者甚至不需要的情况下可以做的范围破解密码开始。
它会增加复杂性而不会增加太多价值。
它不会破坏加盐的目的,正如你所擅长的那样,因为盐并不是要保密的,只是独一无二的。目标不是让您无法从哈希中找出密码,而是无法预先计算哈希,然后可以直接与您的哈希进行比较以查看是否匹配,并确保相同的密码导致不同的密码哈希。
因此,尝试将盐分开和保密并不是构造设计的一部分,您最好利用开发时间和资源来强化和保护您的应用程序和数据库免受损害。
这不是必需的。
这样想吧……
如果您的服务器可以访问盐并且攻击者在您的服务器上获得了 root 权限,那么无论它们位于何处,他都可以访问您的“远程存储的盐”。
由于您使用的是 PHP,请查看 password_hash 和 password_verify 函数。