密码成为目标:为什么旧方法不再有效
\n想象一下:你是一名开发人员,正在编写一个注册系统。看起来能有多简单?获取密码,通过md5处理,保存到数据库。但在2025年,这种方法——直接通向漏洞之路。现代攻击、GPU暴力破解和彩虹表会在几秒钟内将弱哈希化为乌有。Stack Overflow上一个有数千次浏览的问题——「Secure hash and salt for PHP passwords」——仍然具有现实意义,我们将一劳永逸地解决它。
\n在本文中,您将学习如何使用现代算法、内置函数和盐(salt)在PHP中正确地对密码进行哈希处理。我们将社区的最佳答案改编为教育内容,并向您展示即使在2025年也能如何保护用户。
\n\n为什么md5和sha1是邪恶的
\n如果您仍然使用md5或sha1来存储密码——请停下来。这些算法是为速度而设计的,而不是为安全。在2025年,GPU每秒可以破解数十亿个md5哈希。添加盐(随机字符串)也无济于事:彩虹表可以被绕过,但速度仍然是致命的。
\n- \n
- Md5: 2^128种可能性——几分钟内即可破解。 \n
- Sha1: 稍好一些,但同样过时了。 \n
- 不加慢化的盐: 如果哈希很快,盐只能延迟攻击。 \n
相反,我们需要「慢化」算法——那些需要时间和内存的算法。这正是password_hash所使用的。
password_hash 和 password_verify:PHP内置的解决方案
\n自PHP 5.5起,出现了两个函数,它们解决了90%的密码安全问题:password_hash和password_verify。它们会自动生成加密安全的盐,并使用能够抵抗暴力破解的算法。在2025年,这是标准做法,不要再自己造轮子了!
它是如何工作的?
\npassword_hash函数接受一个密码和一个算法(默认是bcrypt,但也可以指定argon2)。它返回一个已经包含盐和参数的字符串。您不需要单独存储盐——它就在哈希内部。
<?php\n// 哈希密码\n$password = "SuperSecret123!";\n$hash = password_hash($password, PASSWORD_DEFAULT);\n\necho $hash; // $2y$10$... (60个字符)\n?>\n\n现在在登录时验证密码:
\n<?php\n$inputPassword = "SuperSecret123!";\n$storedHash = "$2y$10$..."; // 来自数据库\n\nif (password_verify($inputPassword, $storedHash)) {\n echo "密码正确!";\n} else {\n echo "密码错误。";\n}\n?>\n\n一切都非常简单。password_verify会自动从哈希中提取盐并验证密码。无需任何额外操作。
算法选择:bcrypt vs argon2
\n在2025年,您有两个主要选择:
\n- \n
- Bcrypt (PASSWORD_BCRYPT): 久经考验,默认使用。能抵抗攻击,但需要配置cost factor。 \n
- Argon2 (PASSWORD_ARGON2I 或 PASSWORD_ARGON2ID): 密码哈希竞赛的获胜者。更现代,需要更多内存,这使得GPU攻击更加困难。推荐用于新项目。 \n
使用argon2的示例:
\n<?php\n$hash = password_hash($password, PASSWORD_ARGON2ID, [\n 'memory_cost' => 1 << 17, // 128 MB\n 'time_cost' => 4,\n 'threads' => 2\n]);\n?>\n\nmemory_cost参数——内存大小,以千字节为单位。越高越安全,但也越慢。对于生产环境,请在您自己的服务器上进行测试。
盐(salt):它是如何工作的以及为什么不需要单独处理
\n许多新手会问:「如何手动添加盐?」答案是:不需要。password_hash会为bcr生成22个字符的随机盐