首发地址:本人个人博客,转载请注明出处。md5安全吗?经过各种安全事件,很多系统在存储密码的时候不会直接存储明文密码,大部分都改成md5加密(hash)后存储密码,但是这样真的安全吗?下面是测试MD5速度的脚本,测试结果:[root@f4d5945f1d7ctools]#phpspeed-of-md5.phpArray([rounds]=>100[timesofaround]=>1000000[avg]=>0.23415904045105[max]=>0.28906106948853[min]=>0.21188998222351)你有没有发现一个问题:MD5速度太快,容易暴力破解。简单计算:>Math.pow(10,6)/1000000*0.2340.234>Math.pow(36,6)/1000000*0.234/608.489451110400001>Math.pow(62,6)/1000000*0.234/60/6015.6192破解6位密码仅需0.234秒!使用6位数字+小写字母密码,破解仅需8.49分钟!使用6位数字+大小写混合字母密码,破解仅需3.69小时!当然,使用更长的密码会明显增加破解难度:>Math.pow(10,8)/1000000*0.23423.400000000000002>Math.pow(36,8)/1000000*0.234/60/60/247.640505999359999>数学。pow(62,8)/1000000*0.234/60/60/24/3651.6201035231755982使用8位纯数字密码,破解耗时23.4秒!使用8位数字+小写字母密码,破解需要7.64小时!破解8位数字+大小写密码需要1.62年!但是,别忘了,这个速度只是在笔者使用PHP这种解释型语言的弱鸡个人电脑(i5-4460CPU3.20GHz)上运行的,而且只用了一个线程和一个CPU核心。如果你在最新的XeonE7v4系列CPU服务器上运行,充分利用它的48个线程,用C语言重写测试代码,你可以轻而易举地将速度提升数百或数千倍。所以即使使用8位数字+大小写字母,破解也只需要14个小时!更何况很多人的密码使用比较规则的字母或者数字,可以降低暴力破解的难度。。。如果没有加盐或者固定加盐,那么彩虹表破解就更容易了。。。那么如何提高呢密码存储的安全性?密码!提高安全性就是提高密码破解的难度,至少要让暴力破解的难度达到攻击者无法承受的程度。(当然,用户密码的长度当然也很重要,建议至少8个字符,越长越安全)这里不得不插一句:PHP确实是世界上最好的语言--标准库给出了解决方案。password_xxx系列函数在PHP5.5版本中加入,对于之前的版本,还有一个兼容库:password_compat。在这个名为“密码哈希算法”的核心扩展中,提供了一系列简单明了的密码存储封装。功能。简单介绍:password_hash是对密码进行加密(散列)。目前默认使用(也只能使用)bcrypt算法,相当于md5功能的增强版。算法,可以防止基于时间的攻击,相当于$hashedPassword===md5($inputPassword)password_needs_rehash是判断是否需要升级的函数。这个功能很强大。下面详细说说password_hash。Password_hash需要传入一个算法。现在默认且只能使用bcrypt算法。这个算法是什么算法?为什么选择PHP标准库中的bcrypt?bcrypt是一种基于Blowfish算法的密码散列算法,由NielsProvos和DavidMazieres设计。该算法的特殊之处在于其他算法都是关于速度的。该算法中有一个关键参数:成本。顾名思义,值越大,花费的时间越长,呈指数增长--它的一部分加密过程是这样的:EksBlowfishSetup(cost,salt,key)state<-InitState()state<-ExpandKey(state,salt,key)repeat(2^cost)//"^"表示指数关系state<-ExpandKey(state,0,key)state<-ExpandKey(state,0,salt)returnstate比如下面是作者(个人弱PC,i5-4460CPU3.20GHz)的测试结果:成本时间80.02130790.037150100.079283110.175612120.317375130.6663080这个速度与md5相比较简单直接就是蚂蚁与猎豹的区别——即使照片cost=8,一个8位暴力破解大小写字母+数字的密码需要14万年,更何况是一般服务器将至少设置为10或更大(需要540,000年或更长时间)。显然,成本越大越好。越大,占用服务器CPU越多,容易引起DOS攻击。建议根据服务器配置和业务需求设置为10~12。最好限制同一个用户同一个IP同时登录的次数,以防止DOS攻击。一种安全存储密码的方案如上所述,一种安全存储密码的方案应该是这样的:(直接放代码)classUserextendsBaseModel{constPASSWORD_COST=11;//这里配置bcrypt算法的代价,需要时随时升级constPASSWORD_ALGO=PASSWORD_BCRYPT;//默认使用bcrypt(并且现在才使用)/***验证密码是否正确**@paramstring$plainPassword用户密码的明文*@parambool$autoRehash是否自动rehash计算hash值密码(如果需要)*@returnbool*/publicfunctionverifyPassword($plainPassword,$autoRehash=true){if(password_verify($plainPassword,$this->password)){if($autoRehash&&password_needs_rehash($this->密码,self::PASSWORD_ALGO,['cost'=>self::PASSWORD_COST])){$this->updatePassword($plainPassword);}返回真;}返回假;}/***更新密码**@paramstring$newPlainPassword*/publicfunctionupdatePassword($newPlainPassword){$this->password=password_hash($newPlainPassword,self::PASSWORD_AL开始,['成本'=>self::PASSWORD_COST]);$this->保存();这样,当用户注册或修改密码时,调用$user->updatePassword()设置密码,登录时调用$user->verifyPassword()验证密码是否正确。当硬件性能提升到一定程度,cost=11不能满足安全要求时,修改PASSWORD_COST的值可以无缝升级,让存储的密码更加安全。
