Practical PHP Programming

生成安全的数据散列

string sha1 ( string source [, bool raw_output])

SHA意思是“安全散列算法”,它可以将任意长度的字符串转换为用于验证的40位的十六进制数字。哈希(hash)就是一种单向的加密算法,用于检测输入的准确性。单向的意思是你不能通过$hash = sha1($somestring)的方式从$hash得到$something,因为哈希不包含原始文本,所以不可能得到$something。那么,哈希可以用来做什么呢?

好吧,假设用户输入了密码,你怎样验证密码是否正确呢?

<?php
    if ($password == "Frosties") {
        // ........
    }
?>

上面的方式当然可行,但是也就意味着只要能够阅读源码,就可以知道密码。同样地,如果你直接把用户的密码存在数据库当中,万一有人入侵了你的数据库,那估计到时候有你好看。如果你存在数据库或文件中的密码已经加密,即使被入侵,入侵者也拿不到原始密码。

另一方面,即使是授权用户也无法拿到原始密码。一件事情,从不同的方面来看可能会有不同的结果,但对密码进行加密通常来说是值得的。忘记密码的用户只要重置他们的密码就可以了,而不是取回之前的密码。

哈希散列通常也用来检查文件是否下载完整了:如果你得到的哈希值同网站提供的一致,那就说明你下载到的文件不存在问题。

数据的哈希散列处理包括取一个值并将其转换为一个包含字母和数字的半无意义的固定长度的字符串。不管是谁,都没有办法“破解”这个哈希值来获得原始数据。破解哈希值的唯一的方法就是尝试几乎所有可能的输入,当然,这可能花掉相当长的时间来进行尝试。

来看一下下面这段代码:

<?php
    print sha1("hello") . "\n";
    print sha1("Hello") . "\n";
    print sha1("hello") . "\n";
    print sha1("This is a very, very, very, very, very, very, very long test");
?>

输出为:

aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0
aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d
66f52c9f1a93eac0630566c9b82b26f91d727001

在这里有三个关键的地方需要注意:第一,所有的输出都有且仅有40个字符;第二,“hello”和“Hello”虽然原始字符串只有一个字母大小写的区别,但它们的哈希值却是天壤之别;第三,没办法从哈希值来区分原始字符串的长短,因为所有的哈希值都是不可逆的,且都为40个字符。

如果你将用户密码哈希之后存到数据库中,你只要将用户输入的密码进行哈希散列之后的值同你数据库中的值进行对比就可以了。因为sha1()对同样的输入返回的值是一样的。

作者说明:如果你将第二个可选参数设为true,SHA1将返回长度为20位的二进制格式的原始值。