理解php Hash函数,增强密码安全
2024-05-04 22:08:00
供稿:网友
1.声明
密码学是一个复杂的话题,我也不是这方面的专家。许多高校和研究机构在这方面都有长期的研究。在这篇文章里,我希望尽量使用简单易懂的方式向你展示一种安全存储Web程序密码的方法。
2.“Hash”是做什么的?
“Hash将一段数据(小数据或大数据)转换成一段相对短小的数据,如字符串或整数。”
这是依靠单向hash函数来完成的。所谓单向是指很难(或者是实际上不可能)将其反转回来。一个常见的hash函数的例子是md5(),它流行于各种计算机语言和系统。
代码如下:
$data = "Hello World";
$hash = md5($data);
echo $hash; // b10a8db164e0754105b7a99be72e3fe5
使用md5()运算出来的结果总是32个字符的字符串,不过它只包含16进制的字符,从技术上来说它也可以用128位(16字节)的整形数来表示。你可以使用md5()来处理很长的字符串和数据,但是你始终得到的是一个固定长度的hash值,这也可能可以帮助你理解为什么这个函数是“单向”的。
3.使用Hash函数来存储密码
典型的用户注册过程:
用户填写注册表单,其中包含密码字段;
程序将所有用户填写的信息存储到数据库中;
然而密码在存储到数据库前通过hash函数加密处理;
原始的密码不再存储在任何地方,或者说它被丢弃了。
用户登录过程:
用户输入用户名和密码;
程序将密码通过以注册相同的hash函数进行加密;
程序从数据库查到用户,并读取hash后的密码;
程序比较用户名和密码,如果匹配则给用户授权。
如何选择合适的方法来加密密码,我们将在文章的后面讨论这个问题。
4.问题1:hash碰撞
hash碰撞是指对两个不同的内容进行hash得到了相同的hash值。发生hash碰撞的可能性取决于所用的hash算法。
如何产生?
举个例子,一些老式程序使用crc32()来hash密码,这种算法产生一个32位的整数作为hash结果,这意味着只有2^32 (即4,294,967,296) 种可能的输出结果。
让我们来hash一个密码:
代码如下:
echo crc32('supersecretpassword');
// outputs: 323322056
现在我们假设一个人窃取了数据库,得到了hash过的密码。他可能不能将323322056还原为‘supersecretpassword',然而他可以找到另一个密码,也能被hash出同样的值。这只需要一个很简单的程序:
代码如下:
set_time_limit(0);
$i = 0;
while (true) {
if (crc32(base64_encode($i)) == 323322056) {
echo base64_encode($i);
exit;
}
$i++;
}
这个程序可能需要运行一段时间,但是最终它能返回一个字符串。我们可以使用这个字符串来代替‘supersecretpassword',并使用它成功的登录使用该密码的用户帐户。
比如在我的电脑上运行上面的程序几个月后,我得到了一个字符串:‘MTIxMjY5MTAwNg=='。我们来测试一下: