目前认为MD5是部分不安全的。考虑到这一点,我想知道使用哪种机制来保护密码。

这个问题,“双重哈希”密码是否比只哈希一次更不安全? 建议哈希多次可能是一个好主意,而如何实现个别文件的密码保护?建议使用盐。

我用的是PHP。我想要一个安全快捷的密码加密系统。对一个密码进行一百万次哈希运算可能更安全,但也更慢。如何在速度和安全之间取得良好的平衡?此外,我更希望结果具有恒定数量的字符。

哈希机制必须在PHP中可用 必须是安全的 它可以使用盐(在这种情况下,所有的盐都一样好吗?有没有办法生产出好的盐?)

另外,我是否应该在数据库中存储两个字段(例如,一个使用MD5,另一个使用SHA)?这会让它更安全还是更不安全?

以防我不够清楚,我想知道要使用哪个哈希函数,以及如何选择一个好的盐,以便拥有一个安全和快速的密码保护机制。

没有完全涵盖我的问题的相关问题:

PHP中的SHA和MD5有什么区别 简单密码加密 为asp.net存储密钥和密码的安全方法 如何在Tomcat 5.5中实现加盐密码


当前回答

虽然问题已经回答了,但我只是想重申,用于哈希的盐应该是随机的,而不是像第一个答案中建议的电子邮件地址那样。

更多的解释可以在(archive.org的副本)http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/上找到

Recently I had a discussion whether password hashes salted with random bits are more secure than the one salted with guessable or known salts. Let’s see: If the system storing password is compromised as well as the system which stores the random salt, the attacker will have access to hash as well as salt, so whether the salt is random or not, doesn’t matter. The attacker will can generate pre-computed rainbow tables to crack the hash. Here comes the interesting part- it is not so trivial to generate pre-computed tables. Let us take example of WPA security model. Your WPA password is actually never sent to Wireless Access Point. Instead, it is hashed with your SSID (the network name- like Linksys, Dlink etc). A very good explanation of how this works is here. In order to retrieve password from hash, you will need to know the password as well as salt (network name). Church of Wifi has already pre-computed hash tables which has top 1000 SSIDs and about 1 million passwords. The size is of all tables is about 40 GB. As you can read on their site, someone used 15 FGPA arrays for 3 days to generate these tables. Assuming victim is using the SSID as “a387csf3″ and password as “123456″, will it be cracked by those tables? No! .. it cannot. Even if the password is weak, the tables don’t have hashes for SSID a387csf3. This is the beauty of having random salt. It will deter crackers who thrive upon pre-computed tables. Can it stop a determined hacker? Probably not. But using random salts does provide additional layer of defense. While we are on this topic, let us discuss additional advantage of storing random salts on a separate system. Scenario #1 : Password hashes are stored on system X and salt values used for hashing are stored on system Y. These salt values are guessable or known (e.g. username) Scenario#2 : Password hashes are stored on system X and salt values used for hashing are stored on system Y. These salt values are random. In case system X has been compromised, as you can guess, there is a huge advantage of using random salt on a separate system (Scenario #2) . The attacker will need to guess addition values to be able to crack hashes. If a 32 bit salt is used, 2^32= 4,294,967,296 (about 4.2 billion) iterations will can be required for each password guessed.

其他回答

我通常使用SHA1和salt和用户ID(或其他特定于用户的信息),有时我还使用常数salt(因此我有2部分salt)。

SHA1 is now also considered somewhat compromised, but to a far lesser degree than MD5. By using a salt (any salt), you're preventing the use of a generic rainbow table to attack your hashes (some people have even had success using Google as a sort of rainbow table by searching for the hash). An attacker could conceivably generate a rainbow table using your salt, so that's why you should include a user-specific salt. That way, they will have to generate a rainbow table for each and every record in your system, not just one for your entire system! With that type of salting, even MD5 is decently secure.

从PHP 5.5开始,PHP就有了简单安全的散列和验证密码的函数password_hash()和password_verify()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

当使用password_hash()时,它生成一个随机的盐并将其包含在输出的哈希中(以及使用的代价和算法)。password_verify()然后读取该哈希并确定使用的盐和加密方法,并根据提供的明文密码验证它。

提供PASSWORD_DEFAULT指示PHP使用已安装的PHP版本的默认哈希算法。具体哪种算法在未来的版本中会随着时间的推移而改变,因此它将始终是可用的最强算法之一。

不断增加的成本(默认为10)使得哈希更难使用暴力,但也意味着生成哈希并根据它们验证密码将为服务器的CPU带来更多的工作。

请注意,即使默认的哈希算法可能会改变,旧的哈希将继续进行验证,因为所使用的算法存储在哈希中,password_verify()会捕获它。

我不会以两种不同的方式存储哈希密码,因为这样的话,系统至少和正在使用的最弱的哈希算法一样弱。

我只想指出,PHP 5.5包含一个密码哈希API,它提供了crypt()的包装器。这个API极大地简化了哈希、验证和重哈希密码哈希的任务。作者还发布了一个兼容性包(以您只需要使用的单个password.php文件的形式),供那些使用PHP 5.3.7及以后版本并希望立即使用它的用户使用。

它目前只支持BCRYPT,但它的目标是轻松扩展到包括其他密码哈希技术,因为技术和成本存储为哈希的一部分,对您首选的哈希技术/成本的更改不会使当前哈希失效,框架将自动地在验证时使用正确的技术/成本。如果您没有显式地定义自己的盐,它还可以处理生成“安全”盐。

API公开了四个函数:

Password_get_info() -返回关于给定散列的信息 Password_hash()—创建密码散列 Password_needs_rehash()—检查给定的散列是否与给定的选项匹配。有用的检查散列是否符合您当前的技术/成本方案,允许您在必要时重新散列 Password_verify()—验证密码是否与散列匹配

目前,这些函数接受PASSWORD_BCRYPT和PASSWORD_DEFAULT密码常量,它们目前是同义词,区别在于PASSWORD_DEFAULT“在支持更新、更强的散列算法的新PHP版本中可能会改变”。在登录时使用PASSWORD_DEFAULT和password_needs_rehash()(并在必要时重新进行散列)应该确保您的散列对暴力攻击具有合理的弹性,几乎不需要做任何工作。

编辑:我刚刚意识到罗伯特·K的回答中简单提到了这一点。我将把这个答案留在这里,因为我认为它提供了更多关于它如何工作的信息,以及它为那些不了解安全性的人提供的易用性。

在可预见的将来,SHA1和salt应该足够了(当然,这取决于您是为Fort Knox编写代码还是为购物清单编写登录系统)。如果SHA1不够好,可以使用SHA256。

The idea of a salt is to throw the hashing results off balance, so to say. It is known, for example, that the MD5-hash of an empty string is d41d8cd98f00b204e9800998ecf8427e. So, if someone with good enough a memory would see that hash and know that it's the hash of an empty string. But if the string is salted (say, with the string "MY_PERSONAL_SALT"), the hash for the 'empty string' (i.e. "MY_PERSONAL_SALT") becomes aeac2612626724592271634fb14d3ea6, hence non-obvious to backtrace. What I'm trying to say, that it's better to use any salt, than not to. Therefore, it's not too much of an importance to know which salt to use.

实际上有一些网站就是这样做的——你可以给它一个(md5)哈希值,它会吐出一个已知的明文来生成那个特定的哈希值。如果您要访问存储普通md5-哈希值的数据库,那么为这样的服务的管理员输入哈希值并登录就很简单了。但是,如果密码被加密,这样的服务将变得无效。

此外,双重哈希通常被认为是不好的方法,因为它减少了结果空间。所有流行哈希值都是固定长度的。因此,这个固定长度的值是有限的,结果变化不大。这可以被视为另一种形式的盐,但我不建议这样做。