首页 | 新闻 | 交流 | 问吧 | 文档 | 手册 | 下载 | 博客

收藏此问题 发表新评论

PHP密码的安全性

如果你建了个需要用户注册的网站,那么你就有责任保证用户登陆密码的安全。如果把他们的密码用明码存放,那你就失职了。你会觉得用明码存放密码,像Reddit网站一样,可以让用户用得更方便。就算我同意你的看法,但如果你的数据库像Reddit网站一样被偷了呢?那时损失的不单是你自己的网站,因为用户通常在多个网站都用同一个登陆密码,这样,那些网站也跟着倒霉了。

任何数据都不是绝对安全的,想想任何人都可以接触你的服务器(是不是有公司替你管理服务器?),接触你的数据库(是不是有公司替你备份数据?),但你对此却无能为力。也就是说你的数据库被偷的机会是很大的。那么,最简单的(安全措施)就是对用户的登陆密码加密。

哈希方法(Hashing)

Hash是将原密码运用单向算法运算后得出的字符串。换句话说,就是加密很容易,解密极困难(如果应用得法,解密几乎不可能)。 先将加密结果(Hash)放在数据库里,当用户登录时,可将其登录密码加密(Hash)后,再与之前放在数据库中的结果比对。如下例
复制内容到剪贴板
代码:
if( $user->passwordhash == sha1( $_POST['password'] ) )

(shal : Secure Hash Algorithm .译者注)
PHP有好几种加密算法,md5 和sha1 是用的最多的。但两者都没有人们想象的那么安全。应该用更安全的算法,安装加密引擎(PHP 5.1.2以上已内置) 后可有更多算法可用。以下是更棒的例子
复制内容到剪贴板
代码:
if( $user->passwordhash == hash( 'whirlpool', $_POST['password'] ) )
彩虹表 (Rainbow tables)

但还有个问题,偷窃者偷取数据库后,就有大量的时间使用彩虹表来破解。其原理是将常用词(比如从字典中提取每个词)加密后的字符串比对数据库里的字符串。
用不了个把小时,近半的密码可能已被破解。

防范措施就是在每个密码加密时增加一段随机产生的字符(可叫其变形算法或随便什么)。耗时的彩虹表攻击法是基於字典的词。要破解加料后的密码,就要根据增加的每一个字符重建一本字典,攻击会因太耗时而不能成事。每个密码都要附加一段不同的字符,字符本身就根本不用加密。

例子

安全加密方法如下
复制内容到剪贴板
代码:
// get a new salt - 8 hexadecimal characters long

// current PHP installations should not exceed 8 characters

// on dechex( mt_rand() )

// but we future proof it anyway with substr()

function getPasswordSalt()

{

    return substr( str_pad( dechex( mt_rand() ), 8, '0',

                                           STR_PAD_LEFT ), -8 );

}



// calculate the hash from a salt and a password

function getPasswordHash( $salt, $password )

{

    return $salt . ( hash( 'whirlpool', $salt . $password ) );

}



// compare a password to a hash

function comparePassword( $password, $hash )

{

    $salt = substr( $hash, 0, 8 );

    return $hash == getPasswordHash( $salt, $password );

}



// get a new hash for a password

$hash = getPasswordHash( getPasswordSalt(), $password );
加料字符用不着加密,你可将其分存在数据库中,但我个人喜欢把其连成一串。同样的,加料字符用不着变成十六进制,但我喜欢用和哈希字符串一样的十六进制的格式。

最后,正如Thomas Ptacek说的,你没必要用世界上最快的算法来加密,它是留给攻击者用的。


(译者注:原文和对比翻译见英文版)
昵称: goodonyou  时间: 2007-11-24 19:26:00
很好,顶
昵称: PHPChina  时间: 2007-11-24 19:29:00
确实很不错,简单实用!
昵称: dzjzmj  时间: 2007-12-12 19:44:00
应鼓励原创精华!但这篇文章的内容确实很有帮助。
昵称: PHPChina  时间: 2007-12-12 19:45:00
昵称: luzhou  时间: 2007-12-12 21:01:00
对我这样的菜鸟来说可是一头雾水啊!
昵称: MoHock  时间: 2007-12-12 21:56:00
实用的不得了,顶
昵称: s36376149  时间: 2007-12-15 12:45:00
多谢,学习了
昵称: gently  时间: 2007-12-16 12:33:00
引用:
原帖由 lxylxy888666 于 2007-12-16 12:33 发表
多谢,学习了
瞧你这激动样。。。
昵称: lxylxy888666  时间: 2007-12-16 14:34:00
楼主说的是不可逆加密了,很多时候我们需要可逆的加密算法。
比如Discuz论坛,在客户端有个cdb_auth的cookie,里面包含了用户id、md5后的密码、所属组信息,这个cdb_auth在服务器端加密后再用base64编码。客户端每次请求,Discuz会解密这个Cookie,用于验证身份。
Discuz可逆加密的核心东西是非常简单的XOR过程,只是对XOR算子的生成下了很大心思。感兴趣的可以去看下我以前写的介绍:http://blog.csdn.net/carche/archive/2007/06/23/1663829.aspx

最后说一下,Discuz没有采用SessionId来保存用户信息是有道理的,是为了防止cookie欺骗。
昵称: luzhou  时间: 2007-12-17 12:01:00