当前位置:科技动态 > 密码存储中的安全问题和 MD5 的替代方案

密码存储中的安全问题和 MD5 的替代方案

  • 发布:2023-10-09 07:06

md5 安全吗?有多不安全?如何安全地存储密码?... md5安全吗? 经过各种安全事件之后,很多系统在存储密码时不再直接存储明文密码。大多数系统都存储 md5 加密(散列)密码。但这真的安全吗? 这是一个测试MD5速度的脚本。测试结果为: [root@f4d5945f1d7c tools]# php speed-of-md5.php Array ( [rounds] => 100 [rounds of a round] => 1000000 [avg] => 0.23415904045105 [max] => 0. 28906106948853 [min] = > 0.21188998222351) 你有没有发现一个问题:MD5速度太快,很容易进行暴力破解。 只需算一下: > Math.pow(10, 6) / 1000000 * 0.234 0.234 > Math.pow(36, 6) / 1000000 * 0.234 / 60 8.489451110400001 > Math.pow(62, 6) / 1000000 * 0.234 / 60 / 60 3 .69201531296 使用6位纯数字密码,破解仅需0.234秒! 使用6位密码+小写字母,破解仅需8.49分钟! 使用大小写字母混合的6位密码,仅需3.69小时即可破解! 当然,使用更长的密码会显着增加破解难度: > 数学.pow(10, 8) / 1000000 * 0.234 23.400000000000002 > 数学.pow(36, 8) / 1000000 * 0.234 / 60 / 60 / 24 7.640505999359999 > 数学.pow(62, 8) / 10 00000 * 0.234 / 60 / 60 / 24 / 365 1.6201035231755982 使用8位纯数字密码,破解仅需23.4秒! 使用8位数字+小写字母密码,破解需要7.64小时! 使用8位数字+大小写字母混合密码,破解需要1.62年!不过,别忘了,这个速度只是在我这个弱小的个人电脑(i5-4460 CPU 3.20GHz)上使用解释语言PHP才达到的,而且只使用了一个线程和一个CPU核心。如果你在最新的Xeon E7 v4系列CPU的服务器上运行它,充分利用它的48个线程,并用C语言重写测试代码,你可以轻松地将速度提高数百倍或数千倍。所以即使你使用8位数字+大小写字母混合的密码,也只需要14个小时就能破解! 更何况,很多人的密码都使用比较规则的字母或者数字,这样可以降低暴力破解的难度……如果没有盐或者有固定的盐,那么彩虹表破解就更容易了…… 那么如何提高密码存储的安全性呢?加密! 提高安全性意味着密码破解变得更加困难,至少达到攻击者无法承受暴力破解的程度。 (当然,用户密码的长度也很重要,建议至少8个字符,密码越长越安全。) 这里不得不说一句:PHP确实是世界上最好的语言——标准库已经给出了解决方案。 PHP 5.5版本中新增了password_xxx系列函数,对于之前的版本,还有一个兼容库可用:password_compat。 这个名为“密码哈希算法”的核心扩展为封装密码存储提供了一系列简洁明了的功能。简单介绍: password_hash 是对密码进行加密(散列)。目前默认使用bcrypt算法(且只能使用),相当于md5函数的增强版。 password_verify 是验证密码的函数。内部使用的安全字符串比较算法可以防止基于时间的攻击。它相当于 $hashedPassword === md5($inputPassword) password_needs_rehash是判断是否需要升级的函数。这个功能太神奇了。下面我们来详细说说。 password_hash需要传入一个算法。目前唯一可以使用的是bcrypt算法。这是什么样的算法? PHP标准库中为何选择bcrypt?bcrypt 是一种基于 Blowfish 算法的专门用于密码哈希的算法,由 Niels Provos 和 David Mazieres 设计。该算法的特别之处在于其他算法都注重速度。该算法中有一个至关重要的参数:成本。顾名思义,值越大,花费的时间就越长,并且呈指数级增长——其部分加密过程如下: EksBlowfishSetup(cost, salt, key) state <- InitState() state <- ExpandKey(state, salt, key) Repeat (2^cost) // “^”表示指数关系 state <- Exp pandKey(state, 0, key) state <- ExpandKey(state, 0, salt) 返回状态 例如,以下是笔者的测试结果(个人弱PC,i5-4460 CPU 3.20GHz): 成本时间 8 0.021307 9 0.037150 10 0.079283 11 0.175612 12 0.317375 13 0.663080 14 1.330451 15 2.245152 16 4.291169 17 8.318790 1 8 16. 472902 19 35.146999 附件:测试代码 和md5相比,这个速度简直就是蜗牛和猎豹的区别——即使成本=8,一个8位大小写字母+数字的密码也需要14万年才能破解,更何况大多数服务器都会设置为至少 10 或更大(这将需要 540,000 年或更长时间)。显然,成本越大越好。如果较大,则占用服务器的CPU较多,但容易引起DOS攻击。建议根据服务器配置和业务需求设置为10~12。最好限制同一用户同一IP同时尝试登录的次数,防止DOS攻击。 安全存储密码的解决方案 综上所述,一个安全存储密码的解决方案应该是这样的:(直接放代码即可)类用户扩展 BaseModel { const PASSWORD_COST = 11; // 这里配置bcrypt算法的代价,根据需要随时升级 const PASSWORD_ALGO = PASSWORD_BCRYPT; // 默认使用bcrypt(现在只能使用) /** * 验证密码是否正确 * * @param string $plainPassword 用户密码的明文 * @param bool $autoRehash 是否自动重新计算hash密码值(如果需要) * @return bool */ public function verifyPassword($plainPassword, $autoRehash = true) { if (password_verify($plainPassword, $this->password)) { If ($autoRehash && password_needs_rehash($ this->password, self::PASSWORD_ALGO, ['cost' => self::PASSWORD_COST])) { $this->updatePassword ($plainPassword); */ 公共函数 updatePassword($newPlainPassword) { $this->password = password_hash($newPlainPassword, self::PASSWORD_ALGO, ['cost' => self::PASSWORD_COST]);检查密码是否正确。 当硬件性能提升到一定程度,cost=11无法满足安全要求时,修改PASSWORD_COST的值进行无缝升​​级,使存储的密码更加安全。​

相关文章

最新资讯

热门推荐