很多程序可能直接使用了MD5加密, 然后写入数据库的密码字段, 其实存在很大的安全风险, 暴力破解也很容易, 例如数据库泄漏, 可能用户信息能够简单的md5破解后遭受重大损失, 所以放弃传统的MD5密码加密吧! 下面介绍了下我的项目中的密码存储方案。

常见用户表:


CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password` char(64) COLLATE utf8_unicode_ci NOT NULL,
  `salt` char(16) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`),
  UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

 

注册部分:


// 默认生成一个随机的salt字符串, 保证16个字符长度
$salt = dechex(mt_rand(0, 2147483647)) . dechex(mt_rand(0, 2147483647));
// 为了安全存储密码, 我们把用户的输入密码和salt拼接并得到hash字符串, 其实为了更加安全, 可以在密码的中间或者收尾部分位置去插入该salt然后求hash值。
$password = hash('sha256', $_POST['password'] . $salt);
// 接下来我们哈希值65536次。 这样做的目的是为了防止暴力袭击。 现在,攻击者必须对每个密码的猜测计算哈希65537次。而如果密码只进行一次散列,攻击者将能够在相同的时间内进行65537个不同的猜测, 而不是只有一个,对吗?
for($round = 0; $round < 65536; $round++) 
{ 
    $password = hash('sha256', $password . $salt); 
}

// 将salt和password等写入到数据库表中, 到此, 注册结束。

 

登录部分:


// 根据用户名或邮箱等, 得到数据库中保存的密码(也就是上方计算的hash安全码)
$password = '一顿数据库查询后得出的结果...';
$salt = '一顿数据库查询后得出的结果...';

// 将用户表单提交的密码和salt混合hash之后, 并判断是否和数据库保存的一致!
$check_password = hash('sha256', $_POST['password'] . $salt); 
for($round = 0; $round < 65536; $round++) 
{ 
    $check_password = hash('sha256', $check_password . $salt); 
}

if ($check_password == $password) {
    echo '登录成功';
}

总结, 相比明文密码, 甚至简单的MD5后的32位密码, 该算法比其前两者增加了破解难度。