在多个服务器之间使用 phpass 有多安全?
打开“portable_hashes”。 我注意到,无论出于何种原因,它生成的哈希值并不总是相同 - 但在通过“CheckPassword”传递时始终返回有效。我还注意到“PHP_VERSION”用于生成哈希值 - 这两件事结合在一起让我担心......可移植性如何?我可以在服务器、Linux、Windows、64 位、32 位等之间移动哈希值(保存在用户数据库中),并且仍然让它们验证吗?我需要做什么才能使密码不再有效?
我问这个问题的原因是因为我在我的框架中使用 phpass 作为密码,这将为我的几个网站提供支持,其中许多网站目前拥有数千名用户 - 并且在某些情况下我不得不将它们移动到不同的服务器上,当然还有升级php。我也可能将其中一两个从 Apache 切换到 lighthttpd 或类似的东西。不用说,我非常偏执,有一天我会遇到支持噩梦,除了通过电子邮件向每个人发送新密码(这听起来真的很不安全)之外,我无法以任何其他方式解决它。
如果密码有哪怕一丁点的可能无效——我需要采取什么步骤来制作我自己的密码哈希生成器?我已经使用了 16 字节随机盐(每用户),除此之外唯一的问题是拉伸 - 对吧?
With 'portable_hashes' turned on.
I've noticed that for whatever reason, the hashes it generates aren't always the same - but always return as valid when passed through 'CheckPassword'. I've also noticed that 'PHP_VERSION' is used in the generation of the hash - these two things combined have me worried... How portable is portable? Can I move the hashes (Saved in a user database) between servers, linux, windows, 64-bit, 32-bit, etc. - and still have them validate? What would I have to do to make the passwords not validate anymore?
The reason I ask is because I'm using phpass for passwords in my framework which will power several of my sites, many of which currently have several thousands of users - and there have been cases where I've had to move them onto different servers, and of course upgrade php. I also may switch one or two of them off of Apache to, say, lighthttpd or something similar. Needless to say I'm extremely paranoid I'm going to have a support nightmare someday and I won't be able to fix it in any other way than emailing new passwords to everyone (Which sounds really insecure).
If there's even the slightest chance that the passwords will ever be made invalid - what steps would I have to take to make my own password hash generator? I already use a 16-byte random salt (Per-user), and other than that the only other issue is stretching - right?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
根据 PHP 版本,您不需要启用可移植哈希。在 PHP 5.3 及更高版本上,如果系统上不可用,PHP 会提供自己的 bcrypt 实现。 如果您的所有服务器都安装了 PHP 5.3 及更高版本,我强烈建议您关闭可移植哈希。 PHPass“可移植哈希”之所以存在,是因为根据安装的 PHP 版本,bcrypt 可能不可用。
也就是说,PHPass 可移植哈希确实将盐存储在其哈希中。这就是为什么每次使用相同密码运行都是不同的。
此外,PHPass 在生成这些哈希* 期间使用
PHP_VERSION
来检查该版本可用的md5()
函数是否支持$rawMode 参数。如果没有,则使用
pack()
将十六进制数据转换为二进制(请注意,这比简单地使用$rawMode
要慢得多,这就是分支的原因已制成)。再次强调,如果您的所有服务器都运行 PHP 5.3 及更高版本,我强烈建议您关闭便携式模式并让 PHPass 使用
bcrypt
来代替。由于 PHP 5.3+ 在系统版本不可用时提供了自己的实现,因此您的哈希值将可以跨操作系统进行检查。即使您确实关闭了便携式模式,PHPass 仍然会足够智能,以正确的方式检查您的旧哈希值。我的情况和你一样,在我的框架中跨多个站点使用 PHPass。由于我关闭了便携式模式,我已将登录脚本设置为逐步重新哈希登录时未使用 bcrypt 的密码。
* 第 131 行
编辑:有关更多说明,以下是便携式模式下的哈希值是如何生成的(简化,不使用 PHPass 中找到的实际变量,但准确)。请注意,PHPass 使用他们自己的 base64 编码版本。
$final = '$P$'
$final .=encode64_int($ rounds)
(来自构造函数,在 PHP 5+ 上最小值为 5,其他为 3)$final .= genSalt()
(Salt 为 6 个字节...“encode64”格式为 8 个字节)。$hash = md5($salt . $password)
对于
2
$rounds
次,执行$hash = md5($hash . $password)
$final =encode64($hash)
所以最终的哈希本质上是这样的:
Depending on the PHP version, you do not need to have portable hashes on. On PHP 5.3 and above, PHP supplies its own implementation of bcrypt if it isn't available on the system. If all your servers have PHP 5.3 and above, I highly recommend to turn portable hashes off. PHPass "portables hashes" exists because, depending of the version of PHP installed, bcrypt might not be available.
That said, PHPass portable hashes does store the salt in its hash. That's why every run on the same password is different.
Also, PHPass uses
PHP_VERSION
during the generation of those hashes* to check if themd5()
function available with that version supports the$rawMode
parameter. If it doesn't,pack()
is use to transform the hexadecimal data into binary (note that this is considerably slower then simply using$rawMode
, which is why the branch is made).Again, if all your servers are running PHP 5.3 and above, I highly recommend to turn off portable mode and let PHPass use
bcrypt
instead. Since PHP 5.3+ provides its own implementation when the system one isn't available, your hash will be checkable across OSes. Even if you do turn off portable mode, PHPass will still be smart enough to check your old hashes the proper way.I was in the same situation as you, using PHPass in my framework across multiple sites. Since I turned off portable mode, I've set my login script to progressively re-hash passwords which are not using bcrypt on login.
* Line 131
EDIT: For more explanation, here is how hashes in portable mode are generated (simplified, does not use actual variables found in PHPass, but accurate). Note that PHPass uses their own version of base64 encoding.
$final = '$P$'
$final .= encode64_int($rounds)
(from constructor, minimum is 5 on PHP 5+, 3 other)$final .= genSalt()
(Salt is 6 bytes... 8 bytes in "encode64" format).$hash = md5($salt . $password)
For
2
$rounds
times, do$hash = md5($hash . $password)
$final = encode64($hash)
So the final hash essentially is this:
我能看到的 PHP_VERSION 的唯一用途是这一行:
现在,这就是确定最大迭代次数。它位于生成盐的 gensalt_private 方法中。因此,只有在存储新密码并生成盐时才会发生这种情况。因此之前生成的所有盐都是 100% 可移植的。所以根本不存在真正的可移植性问题...
至于其余的,只要您使用的是相当新的 php 版本(5.0+),就根本不应该有任何可移植性问题我可以告诉(因为
hash
函数是内置的)...The only use that I can see of
PHP_VERSION
is in this line:Now, all that's saying is determining the maximum number of iterations. And it's in the
gensalt_private
method which generates salts. So this would only happen when storing a new password and generating the salt. So all previously generated salts are 100% portable. So there's no real portability issue with that at all...As far as the rest, as long as you're using a reasonably recent version of php (5.0+), you shouldn't have any portability problem at all as far as I can tell (since the
hash
function is built in)...