在apache上应用basic auth的时候,会有一步是使用apache提供的htpasswd命令来生成passwd文件。如下:
/usr/local/apache-2.2.4/bin/htpasswd -c ./passwd kevin
这样,就为用户名为“kevin”的用户在当前目录下的passwd文件中创建了一条记录,内容包含用户名及将用户输入的密码加密后字符串。如果文件已存在,则可忽略参数“-c”。
用久了,就会发现,相同的用户名和密码,每一次使用htpasswd命令之后生成的加密字符串都是不同的。那么在随后的应用中,apache又是怎么来校验“用户输入密码经加密后的结果”与“文件中已存在的加密结果”是否匹配呢?
htpasswd默认情况,是使用系统库中的crypt()函数来对密码明文进行单向加密的。在网上找到该函数的说明:
crypt()将使用Data Encryption Standard(DES)演算法将参数key所指的字符串加以编码,key字符串长度仅取前8个字符,超过此长度的字符没有意义。参数salt为两个字 符组成的字符串,由a-z,A-Z,0-9,".",和"/"所组成,用来决定使用4096种不同内建表格的哪一个。
函数执行成功后会返回指向编码过的字符串指针,参数key所指的字符串不会有所更动。编码过的字符串长度为13个字符,前两个字符为参数salt代表的字符串。
默认情况下,htpasswd在对密码明文加密的时候,会随机生成一个两位的salt值。加密后的13位字符串的头两位即是这个salt的值。
在应用过程中,apache根据用户输入的用户名查找出密码文件中已存在的加密字符串,并取该字符串的头两位作为salt,以此对用户输入的密码明文进行crypt()加密,如果结果与密码文件中的加密字符串相同,则匹配上了。
综上所述,对于同一个字符串,crypt()函数的加密结果受到第二个可选参数“salt”(干扰串)影响,而加密结果中又含有这个干扰串。这就明白了虽然用htpasswd每次生成的加密结果不同(随机生成salt并包含在结果中)但apache又可以进行正确校验(salt已知)的原因了。
还有,因为htpasswd默认使用crypt()函数进行加密,所以,在这种情况下密码内容超过8位的字符没有意义。即,“12345678”与“123456789”的加密结果是一样的。