快速提示:如何在 PHP 中散列密码
了解如何在任何编程语言中对密码进行哈希处理都很重要,在这篇快速提示文章中,我们将解释如何在 PHP 中执行此操作,以及为什么对密码进行哈希处理如此重要。
每个 PHP 程序员在某个时候都需要编写一个依赖于用户登录才能正常运行的应用程序。 用户名和密码通常存储在数据库中,然后用于身份验证。 众所周知,密码永远不应以明文形式存储在数据库中:如果数据库遭到破坏,所有密码都将被公开供恶意行为者使用。 这就是为什么我们需要学习如何散列密码。
请注意我们是如何使用散列一词而不是加密的? 这是因为散列和加密是非常不同的过程,经常被混淆。
哈希
散列函数采用类似的字符串 mypassword123
并将其转换为字符串的加密版本,称为散列。 例如, mypassword123
可能会被散列以产生看似随机的数字和字母字符串,例如 9c87baa223f464954940f859bcf2e233
. 散列是一种单向函数。 一旦你散列了一些东西,你就会得到一个固定长度的字符串——一个不能轻易逆转的过程。
我们可以比较两个哈希来检查它们是否都来自同一个原始字符串。 在本文的后面,我们将了解如何使用 PHP 实现此过程。
加密
与哈希类似,加密会将输入字符串转换为看似随机的数字和字母字符串。 但是,加密是一个可逆过程——如果您知道加密密钥。 因为这是一个可逆的过程,所以它不是密码的好选择,但对于点对点安全消息传递之类的东西来说是极好的。
如果我们加密密码而不是对其进行哈希处理,并且我们正在使用的数据库以某种方式被恶意第三方访问,则所有用户帐户都将受到威胁——这显然不是一个好场景。
盐
密码在散列之前也应该加盐。 加盐是在对密码进行哈希处理之前将随机字符串添加到密码中的操作。
通过加盐密码,我们可以防止字典攻击(攻击者系统地输入字典中的每个单词作为密码)和彩虹表攻击(攻击者使用常用密码的哈希列表)。
在加盐之上,我们应该在散列时使用某种程度上安全的算法。 这意味着它应该是一种尚未被破解的算法,最好是一种专用算法而不是通用算法(如 SHA512)。
截至 2023 年,推荐的哈希算法为:
- Argon2 Scrypt bcrypt PBKDF2
使用 PHP 进行哈希处理
自从 PHP5.5 引入了 password_hash()
功能。
目前,它使用 bcrypt(默认情况下)并支持其他哈希算法,如 Argon2。 这 password_hash()
函数还负责为我们加盐。
最后,它返回哈希密码。 成本和盐作为散列的一部分返回。
简单来说,密码哈希的成本是指生成哈希所需的计算量。 这就像衡量创建散列的“难度”。 成本越高,难度越大。
想象一下,你想做一个蛋糕,蛋糕的食谱上写着“鸡蛋打五分钟”。 这就是制作蛋糕的“成本”。 如果你想让蛋糕更“安全”,你可以把食谱改成“鸡蛋打十分钟”。 现在做蛋糕的时间变长了,等于增加了做蛋糕的“成本”。
我们可以在 password_hash()
文档:
…验证散列所需的所有信息都包含在其中。 这允许 [
password_verify()
] 功能来验证散列,而不需要单独存储盐或算法信息。
这确保我们不必在我们的数据库中存储额外的信息来验证哈希返回。
在实践中,它看起来像这样:
<?php
$password = "sitepoint";
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
if (password_verify($password, $hashed_password)) {
//if the password entered matches the hashed password, we're in
} else {
// redirect to the homepage
}
有关的更多信息 password_hash()
功能可以在这里找到,而 password_verify()
可以在这里找到。
结论
对于 PHP 程序员来说,了解散列和加密之间的区别,并使用散列来存储密码以保护用户帐户免受损害是很重要的。 的介绍 password_hash()
PHP 5.5 中的函数使程序员可以轻松地使用各种算法(包括 Argon2 和 bcrypt)安全地散列密码。
正如 Tom Butler 在 PHP & MySQL: Novice to Ninja 中所描述的:
对我们来说幸运的是,PHP 包含一种非常安全的散列密码方式。 它是由比你我更了解这些东西的人创建的,它避免了像我们这样的开发人员需要完全了解可能发生的安全问题。 出于这个原因,强烈建议我们使用内置的 PHP 算法来散列密码,而不是创建我们自己的。
确保您考虑到这一点并及时了解最新推荐的哈希算法,以确保您的应用程序尽可能安全。