password_needs_rehash 函数用于检查现有密码的哈希值是否需要使用新的算法或加密参数进行更新。它会对比当前密码的哈希与所指定的加密参数(如算法、成本因子等),如果现有密码哈希不符合新要求,则返回 true,否则返回 false。
<span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">password_needs_rehash</span></span><span>(</span><span><span class="hljs-variable">$hashedPassword</span></span><span>, PASSWORD_BCRYPT, [</span><span><span class="hljs-string">'cost'</span></span><span> => </span><span><span class="hljs-number">12</span></span><span>])) {
</span><span><span class="hljs-variable">$newHash</span></span><span> = </span><span><span class="hljs-title function_ invoke__">password_hash</span></span><span>(</span><span><span class="hljs-variable">$password</span></span><span>, PASSWORD_BCRYPT, [</span><span><span class="hljs-string">'cost'</span></span><span> => </span><span><span class="hljs-number">12</span></span><span>]);
</span><span><span class="hljs-comment">// 更新数据库中的密码</span></span><span>
}
</span></span>
在这个例子中,password_needs_rehash 检查 $hashedPassword 是否符合指定的加密参数(如 cost 参数),如果不符合,密码就需要重新加密。
随着密码哈希算法的不断更新和升级,使用较旧算法加密的密码可能会面临安全隐患。例如,PHP 最初使用 MD5 和 SHA-1 等算法进行加密,但这些算法已被证明易受攻击。随着 bcrypt 和 Argon2 等现代加密算法的出现,使用这些算法加密的密码更加安全。
password_needs_rehash 函数的引入,允许开发者在密码存储时灵活地进行更新。例如,当我们决定将 bcrypt 更换为 Argon2 时,原本使用 bcrypt 加密的密码可以通过 password_needs_rehash 来检测并更新到新的加密方式。这样,即便是之前存储在数据库中的密码,也能在用户下次登录时自动迁移到新的加密算法。
加密算法本身的安全性不仅仅依赖于算法本身,还与算法的参数设置(如 bcrypt 中的 cost 参数)有关。cost 参数决定了哈希计算的时间复杂度,较高的值能提供更高的安全性,但也会导致更长的计算时间。
假设你在最初使用 cost 为 10 的 bcrypt 算法存储密码,但随着时间的推移,你发现服务器的处理能力更强,可以使用更高的 cost 值以提升安全性。使用 password_needs_rehash,可以检查存储在数据库中的旧密码是否使用了较低的 cost,并根据需要进行更新。
<span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">password_needs_rehash</span></span><span>(</span><span><span class="hljs-variable">$hashedPassword</span></span><span>, PASSWORD_BCRYPT, [</span><span><span class="hljs-string">'cost'</span></span><span> => </span><span><span class="hljs-number">14</span></span><span>])) {
</span><span><span class="hljs-variable">$newHash</span></span><span> = </span><span><span class="hljs-title function_ invoke__">password_hash</span></span><span>(</span><span><span class="hljs-variable">$password</span></span><span>, PASSWORD_BCRYPT, [</span><span><span class="hljs-string">'cost'</span></span><span> => </span><span><span class="hljs-number">14</span></span><span>]);
</span><span><span class="hljs-comment">// 更新数据库中的密码</span></span><span>
}
</span></span>
在这个例子中,如果原始哈希的 cost 低于 14,则需要重新加密。
尽管 password_needs_rehash 提供了一种检测哈希是否需要更新的简单方法,但这一过程仍然可能对性能产生一定影响。特别是在用户量较大或数据库访问频繁的情况下,每次用户登录时都进行哈希检查可能会增加服务器的负担。
为了降低性能影响,推荐在密码登录成功时,在后台异步处理密码的重新加密。这意味着,密码重新加密并不影响用户的即时体验,而是在后台逐步更新数据库中的密码哈希。
通过定期检查密码的哈希是否符合当前的安全标准,使用 password_needs_rehash 可以显著提升系统的安全性。如果不进行更新,可能会有以下风险:
旧算法的安全性问题:老旧的加密算法如 MD5 和 SHA1 已经不再安全,攻击者可能通过彩虹表或其他方式轻松破解这些密码。
参数设置不当:如果 cost 设置过低,可能会让密码容易受到暴力破解攻击,攻击者通过试验大量可能的密码组合来破解哈希。
定期检测并更新密码哈希,有助于确保密码存储始终符合当前的最佳安全实践。