X

曜彤.手记

随记,关于互联网技术、产品与创业

基于 PHP 实现的优化盐值加密算法

通常在开发网站注册登录模块时,我们会在网站的后端数据库中存储用户密码对应的 MD5 值,即用户密码的 Hash 值,而不会直接存储用户的明文密码。这种做法确实可以大大提高网站运行的安全性,即使网站的数据库泄露也不会轻易的将明文密码展示给黑客。但随着时间的推移,这种方式的安全性也在慢慢降低。

当黑客获得用户明文密码的散列值后,便可以通过查询散列值字典(例如 MD5 密码破解网站),来得到某用户的明文密码。随着时间推移,这些 MD5 密码破解网站的破解数据库信息越来越多,散列值被破解的几率也会越来越大。因此,很多企业便逐渐开始采用一种名为“盐值加密”的新型加密方法,但其本身还是基于 MD5 的。

“盐值加密”的基本想法是这样的:当用户首次提供密码时,由系统自动向这个密码加入一些“盐值”,即一些随机信息,然后再进行散列存储到数据库中。而当用户登录时,系统为用户提供的代码加入同样的“盐值”信息,然后进行散列,最后通过比较两者的散列值是否相等,来判断密码是否正确。

由于密码和“盐值”混合在一起,随机的“盐值”使得散列值被破解的几率大大降低,并且黑客也无法确定对应明文密码的正确长度及信息是否正确。解密的过程变得更加复杂,因此安全性得以相对提高。现在大多数论坛程序所使用的“盐值加密”算法如下:

function saltPwd($password, $salt) {
  return md5(md5($salt) . $password);
  // 或者采用如下方式,但本质原理上是一样的;
  // return md5($salt . $password);
}

将密码明文与“盐值”的散列值进行组合,然后再次进行散列来得到最后加入了“盐值”的加密信息。这种方法虽然采用了“盐值加密”,但也并不是最佳的密码安全防范手段。如果这个全局的“盐值”信息被泄露出去,那么黑客还可以继续通过散列字典或者“彩虹表”来推断用户的真实密码信息。所以我们有了如下经过优化的“盐值加密”算法:

function optimizedSaltPwd($password, $salt, $saltGain = 1) {
  // 过滤参数;
  if (!is_numeric($saltGain)) exit;
  if (intval($saltGain) < 0 || intval($saltGain) > 35) exit;
    
  // 对 MD5 后的盐值进行变换,添加信息增益;
  $tempSaltMd5 = md5($salt);
  for ($i = 0; $i < strlen($tempSaltMd5); $i++) {
    if (ord($tempSaltMd5[$i]) < 91 && ord($tempSaltMd5[$i]) > 32) {
      // 每一个字符添加同样的增益;
      $tempSaltMd5[$i] = chr(ord($tempSaltMd5[$i]) + $saltGain);
    }
  }

  // 返回整个哈希值;
  return md5($password . $tempSaltMd5);
}

这里通过使用 $saltGain(盐值增益)和 $salt(盐值)来控制最后产生的加密信息。这种优化的“盐值加密”算法其改进点在于:对已经哈希化的数据中又隐藏了自定义的增益信息,这些增益信息的添加方式是由具体的算法决定的。当然,上述算法只是哈希增益改进算法中的一个例子,具体的改进优化方法还有很多。但最基本的思想就是尽可能增加反向哈希解密的复杂度。




评论 | Comments


Loading ...