我相信他是对的.据我所知,有三种方法可以打破哈希:
>使用彩虹桌(可以用长/随机盐保护)
>碰撞(可通过多种盐或哈希来防止 – 如下例所示)>生成时间(如果我们为每个用户使用足够长的盐值,这并不重要 – AFAIK)我和我的朋友认为Blowfish并不是真的有需要,也可能是有害的,因为它会减慢密码验证过程,并且它可以与DDOS攻击一起使用,即使使用较少的资源,也可以分解服务器.
所以,我想确保遵循算法真的安全吗?并且,是否有真正的理由选择Blowfish哈希算法?
// return a 256 bit salt + 128 bit md5 binary hash value function hash(password, salt=null) { salt = (salt != null) ? salt : Random256BitBinaryValueGenerator(); // What about using another user-specified parameter, like email address as salt? return salt + md5(salt + password) + md5(password + salt); // Or just use a non-cryptographic hash algorithm like crc32 to prevent collisions: // return salt + md5(salt + password) + crc32(salt + password); // Or even use two different salts: // return salt + md5(salt + password) + md5('C' + salt + password); } // check password function check(password, hash_value) { return hash(password, substring(hash_value, 0, 32)) == hash_value; }MD5的 collision resistance属性已经被打破了很长时间.请注意, preimage resistance和第二个preimage阻力尚未被破解,但是因为有更好的算法(SHA-2),移动到这些算法是明智的,而不是依赖于已经开始失去其加密的加密哈希属性.注意:当存储散列密码时,碰撞阻力属性无关紧要 – 您需要确保的是,前映像电阻属性是合理的 – 在给定特定散列值(和盐)的情况下找到原始密码在计算上是不可行的.正如我所提到的,由于其中一个加密属性已被破坏,我担心其他人将很快跟进.
当您存储密码哈希时,您应该建立一些保护,以便在攻击者设法提取这些哈希值时无法检索原始密码.这很重要,因为如果攻击者设法只检索密码表,那么他们就可以使用这些数据直接登录到您的系统,或者登录到用户重复使用相同密码的其他系统.
存储密码时,使用慢速算法很重要,例如bcrypt,scrypt或pbkdf2.合法用户在首次登录时只需要经历一次延迟.攻击者必须经历他们猜测的每个密码的延迟 – 记住彩虹表将不会在这里使用,因为密码被腌制.攻击者将根据您选择的算法和迭代计数对每个密码猜测进行散列.
调整系统的迭代次数非常重要,因此使用正确的“强度”不会导致合法用户在登录系统时出现任何真正的烦恼.这被称为“轮次”数或“迭代次数”.例如,迭代大约一秒应该就足够了.可以安全地假设攻击者可以以系统硬件速度的十倍速度运行哈希值.因此,这限制了攻击者每秒10次猜测,而不是MD5的20亿次.
关于DoS攻击
是的,您的应用程序在登录时执行的额外处理可能是攻击者向您的应用程序提交真正长密码的目标,或者是为了消耗服务器上的CPU和内存资源而反复使用登录请求命中它. You are right to be concerned.
可以通过以下方式减轻这些类型的攻击:
>记录每次登录尝试的用户名和IP地址.在说出6次尝试失败后,如果再次重复该用户名或IP,则会引起应用程序的响应延迟.这也有助于缓解一般的密码猜测攻击.
>例如,你可以人为地延迟1秒,然后是2秒,然后是4,直到合理的值(例如16秒).
>这样做的好处是,攻击者无法故意锁定其他帐户,因为合法用户只需要等待16秒.>攻击者可以使用僵尸网络和随机用户名来绕过这些检查,但是如果没有这种控制,他们需要大量的IP地址,而更随意的攻击者也不会意识到响应的延迟是人为的.>监控系统上的登录尝试次数.一旦超过设定的阈值速率(例如每秒10个),引入CAPTCHA以解决以继续登录过程.您选择的阈值速率在很大程度上取决于系统的用户群和容量.>实施双因素身份验证.只有在验证一次性密码后才能通过散列验证密码.
精彩评论