密码散列方法

时间:2014-04-30 10:17:13

标签: php security encryption hash

我正在创建一个基于PHP的CMS(使用MVC架构)。我想哈希存储在数据库中的用户密码。我已经阅读了很多关于这个主题的艺术和教程,但我遇到了反对意见/观点和建议。我有点困惑。我正在寻找实现密码哈希的最佳方法。这些是我遇到的概念/方法:

首先,许多人混淆了单向散列和双向加密。如果我没有弄错的话,双向加密是关于使用公私密钥对进行不对称加密的问题,而且它是为了保护数据并且只能由知道另一个密钥(密钥)的人才能读取。所以这就是我们现在不关心的。

PHP为哈希提供了许多函数,其中一些函数直接在给定数据上使用散列算法(md5()sha1()sha256()ripemd160()等。)其中一些接受给定数据和支持的算法并生成哈希(hash()hash_init()hash_hmac()等) 散列/加密方法的负载有什么区别? (hash_pbkdf2()crypt()bcrpytpassword_hash()以及上面列出的其他人 正如我所知,在哈希中使用salt是一个好习惯,但是多次哈希是一个坏主意(即使这么多也说明它是好的)。有些功能使用其他人使用密钥......

问题1: 有人可以澄清例如:md5('myPassword');hash('md5', 'myPassword');之间的区别(我知道md5是一种易于破解的方法,不建议用来存储密码)

问题2: salt 之间的区别是什么?那么hash_hmac('sha1', 'myPassword', 'HaCK_MeIF_youCAN');sha1('myPassword'.'HaCK_MeIF_youCAN');之间有什么区别? (注意hash_hamc将其第三个参数称为“密钥”)

问题3: 多次散列真的是一种不好的做法吗? 喜欢:

hash = sha512(password)

for i in range(10000):
    hash = sha512(hash) + salt

return hash

问题4: 哈希密码的最佳方法是什么?

由于这是一个重要且敏感的问题,我认为不熟悉像我这样的话题的其他人希望清楚地说明这个问题,并希望一劳永逸地得到准确可靠的答案,我请你回答一下如果您是IT安全专家,或者您拥有本主题的任何认证或学位! (对于在互联网上获得知识的自称安全专家:您使用散列密码完成数百个系统/网站的事实并不意味着它们是安全的!)

最后一个请求:简单(初学者)webprogrammers不是外星人也不是理论数学家。所以请尝试用类似人类的英语来解释:)

2 个答案:

答案 0 :(得分:2)

关于Stack Exchange上的密码散列问题已经有很多问题,所以这基本上是一个重复的问题,但由于你不知道该相信什么,我会给你一些指示。

Re:问题1 :可能它们只是相同代码的不同接口。 (我没有检查过。如果你想确保在两者中输入相同的输入并比较输出。或者只是查阅文档或源代码。)

Re:问题2 :密钥是您通常不应发布的私有信息(非对称加密中的公钥除外)。通常密码散列中没有密钥。 salt是一段随机的公共信息,用于区分您的密码散列与世界上其他所有预先计算的散列表。这是对rainbow tables的主要防御。

HMAC(基本上m,kHash(k||Hash(k||m))用于连接操作||)被设计为所谓的message authentication code。它(ab)用于许多其他目的,因为它具有通用的设计,如果实例化具有良好的加密散列函数。在这种情况下,使用salt作为密钥,密码作为HMAC中的消息与Hash(password||salt)实际上没有区别。

回复:问题3 :不,这是一个很好的做法。密码存储的主要攻击方案是您的数据库被泄露(如果您的数据足够重要,人们会关注,通常会发布所有密码数据)。大多数非技术人员(显然甚至是一些具有IT背景的人)经常重复使用他们的密码(即使每个人都得到他们的密码哈希海峡也是bad practice)。因此,如果您将密码保存为明文,那么在您的数据库泄露事件中,很多人会突然知道登录信息。要防止这种情况,您需要在密码上使用单向函数。不幸的是,密码在大多数情况下几乎没有熵(因为没有人喜欢记住加密安全密码),因此如果你使用快速散列函数,你可以尝试每个可能的密码并将哈希值与数据库中的哈希值进行比较。作为极端示例,我们假设我只使用密码catdog,并且您拥有密码的sha1哈希:8f6abfbac8c81b55f9005f7ec09e32d29e40eb40生成的echo $password | sha1sum。为读者练习:使用了哪个密码?

为了缓解此问题,您希望使用慢速散列函数,以便尝试每个可能的密码需要花费大量时间。减慢散列的一种方法是迭代几千(甚至几十万)次的散列。还有其他缓慢的散列概念,如bcrypt,它们不仅仅是迭代散列。

回复:问题4 :可以在security.stackexchange.com上找到深入讨论:https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords。 tl,dr版本是CodeInChaos的评论:只需使用password_hash,它几​​乎是万无一失的。除了盐之外,还可以在此处找到有关辣椒预先主题的资源:https://security.stackexchange.com/a/3289/10727

答案 1 :(得分:0)

我会尝试回答您的一些问题,但首先要谈谈加密问题。加密的问题是它是双向的,如果你知道密钥就可以检索密码。仅存储哈希(单向)将更好地保护密码,因为即使所有代码(包括密钥)都已知,也无法检索密码。

问题1& 2: 避免所有快速哈希算法都很重要,包括MD5,SHA *。因为它们如此之快,所以它们很容易受到暴力破坏。它是例如可以使用通用硬件计算每秒8 Giga个MD5哈希值。

问题2: 应该为每个密码随机生成一个salt,但不是秘密的,可以使用密码在数据库中存储明文。密钥(有时称为胡椒)应保密,不存储在数据库中。

问题3: 多次散列是一件好事,但前提是正确完成。像BCrypt和PBKDF2这样的适当算法以安全的方式完成它们,并且它们具有决定迭代次数的成本因子。这个成本因素可以适应未来和更快的硬件。

问题4: 目前,您可以做的最好的事情是使用PHP函数password_hash()来创建BCrypt哈希。早期版本也存在compatibility pack。我写了一篇关于安全存储密码的tutorial,我试图更深入地回答这些问题并以一种希望可以理解的形式,所以你好好看看它。