用户密码安全

内容来源(公众号:PHP版WEB项目)2011年,国内某大型研发人员社区遭到攻击,其数据库中超过600万用户资料遭到泄露。其中一个重要原因是其数据库竟然使用明文来存储用户名、密码,导致攻击者只要得到用户数据,就能直接获得密码信息。

1.加密密码

一般在存储用户密码之前应该先对密码进行加密(如使用MD5、SHA等算法),然后将其存储在数据库中。

用MD5加密密码的代码如下。

用SHA1加密密码的代码如下。

这种较复杂的密码,让攻击者束手无策,但对于较常见的密码,攻击者在得到了数据之后也能有效破译。有一些攻击者将用户常用的密码总结出来,再使用这些加密算法得出其加密后的值,将加密后的值和原始密码保存起来,形成一张可通过密码对原文进行反查的数据表,称其为彩虹表。攻击者只需要用彩虹表与加密后的密码比对,就能得到用户的原始密码。

不建议使用des和MD5等弱加密算法对密码等敏感信息进行加密,散列算法推荐使用SHA256或SHA512。

PHP内置了hash()函数,只需要将加密方式传给hash()函数,直接指明使用SHA256、SHA512等加密方式即可。

2.密码加盐

使用盐(salt)来混淆加密后的值,可以加大攻击者直接从字典密码库中碰撞出用户密码的难度。如果所有用户的salt都一样,且混淆方法已知,那么攻击者依然可以针对常见密码与salt混合生成一张具有针对性的彩虹表。

为了加大安全系数,应该采用随机salt,每次写入用户的密码时(如注册或修改密码),随机生成一个salt(一个随机字串),并将salt与密码混合(可以是各种混合方式,而不仅限于将两个连接在一起),再进行散列计算。这样,即使攻击者拥有了彩虹表,也不能立即猜测出哪些散列值对应哪些常规的密码,因为即使用户输入常规密码,但其混合了salt的散列值与原密码已经不一样了。

使用加盐方式加密用户密码的代码如下。

$password=$_POST['password'];$salt=rand(1,10000);$password=sha1($password.$salt);

然而在salt对于不同用户各异的情况下,也难以对所有用户生成一张彩虹表。但攻击者依然可以针对某一个用户,使用暴力穷举的方式来破译密码。如果用户的密码长度较短且全是数字,再加上若使用的salt过于简单,而MD5、SHA等算法由于本身特性使得加密过程比较快,就很容易被穷举破解。

可以增加普通MD5等快速算法的迭代次数生成复杂的salt,或者使用mcrypt这样更为复杂的加密算法,迫使攻击者在暴力破译的时候需要更长的时间。由于将加密算法控制在微秒级即可给攻击者的破译带来灾难性打击,而同时单个用户登录时验证的耗时又不算太长,这种方法可以说有效地解决了攻击者破译密码的危险。

多次加密的代码如下。

$password=MD5($_POST['password']);$salt= MD5(rand(1,10000));$password=sha1($password.$salt);

生成较长、较复杂的随机salt的代码如下。

$password=$_POST['password'];$salt=base64_encode(mcrypt_create_iv(32,MCRYPT_DEV_RANDOM));$password=sha1($password.$salt);

使用password_hash()函数,指定第二个参数为PASSWORD_BCRYPT进行加密密码的代码如下。

$password=$_POST['password'];$password= password_hash($password,PASSWORD_BCRYPT);

除了以上方式外,还可以用自己的方式对字符串进行混淆,创造更为复杂的密码加密方式。

bcrypt其实就是blowfish和crypt()[1]函数的结合。通过CRYPT_BLOWFISH判断blowfish是否可用,然后生成一个salt。不过这里需要注意的是,crypt()的salt必须以$2a$或者$2y$开头。

6.1.3 定期修改

如果攻击者毅力很好,坚持对你的密码进行长期穷举(数周或者数月),那么定期修改密码会让攻击者无法将密码进行顺利穷举。比如A到Z,你原来密码是M,人家穷举到L的时候,你突然把密码改成B了,就可以避免密码被破获。

如果你的密码已经泄露了,比如你把密码写在一个固定的地方,或你曾把密码告诉别人,人家一直在使用你的账号,你却不知道,定期修改密码,可以降低因为泄露而带来的风险。

一个完整的密码安全策略,用户应该周期性地进行密码修改。例如,在同一个密码使用了三个月、半年或更长时间后,应该主动进行密码修改,减少被破解的可能性,同时防止密码泄露造成的损失。

你可能感兴趣的:(用户密码安全)