17.2.2 密码的加密
无论将数据保存在数据库中还是文件中,都没有必要冒险以普通文本格式存储密码。只要稍微做一点工作,就可以通过一种使用单向哈希的算法来提高密码的安全性。
PHP提供了许多单向的哈希函数。最早的也是安全性最低的是UNIX Crypt算法,它由crypt()函数实现。md5()函数实现的消息摘要5(Message Digest 5)算法更强大一些。而功能更强大的加密的哈希算法1(SHA-1)。PHP的sha1()函数提供了一个功能强大的单向加密哈希函数。该函数原型如下所示:
string sha1(string str[,bool raw_output])
给定字符串str,该函数将返回一个40个字符的伪随机字符串。如果将raw_output参数设置为true,将得到一个20个字符的二进制字符串数据。例如,给定字符串"password",sha1()函数将返回如下所示的结果:
"5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8"
这个字符串无法解密,即使是字符串的创建者也无法还原成"password"字符串,因此初看起来,这个函数的作用并不大。但是真正使得该函数功能强大的原因在于它的输出是确定的。假设使用相同的字符串,sha1()函数每次运行都将返回相同的结果。
因此,我们就可以不使用如下所示的PHP代码:
if(($name=='username')&&
($password=='password')){
//OK passwords match
}
可以使用如下代码:
if(($name=='username')&&
(sha1($password)=='5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8')){
//OK passwords match}
在对字符串使用sha1()函数之前,并不需要知道加密结果表示什么。我们只需要知道输入的密码是否与最初通过sha1()运行的结果密码相同。
正如我们已经提到的,将用户名和密码硬编码到脚本中是一个非常糟糕的主意。可以使用一个独立的文件或者数据库存储它们。
如果要使用一个MySQL数据库来保存身份验证数据,可以使用PHP的shal()函数,或者MySQL的SHA1()函数。MySQL提供了比PHP更广泛的哈希算法,但是二者的作用都是相同的。
要使用SHA1()函数,可以重新编写程序清单17-2中的SQL查询语句,如下所示:
select count(*)from authorized_users where
name='".$name."'and
password=sha1('".$password."')
该查询将计算表authorized_users中具有用户名与$name的内容相同,并且密码值与已经过SHA1()函数处理后的密码相吻合的记录行数。假设我们强制用户使用唯一的用户名,该查询的结果就是0或1。
请记住,这个哈希函数通常将返回固定大小的数据。在SHA1这种情况下,它是用40个字符的字符串来表示。请确认数据库列具有这样的宽度。
通过程序清单17-3,可以看到我们创建了一个用户('username'),其密码为未加密的密码,而另一个用户则具有加密的密码('testuser'),从而对这两种可能的方法进行比较。