关于密码加密的部分几乎都采用了MD5,这主要是因为许多教程推荐此方式。然而,在实际项目中,采用MD5加密密码并不安全,存在明显的安全隐患。

哈希算法大致可以分为两类:

  1. 加密哈希算法:此类算法提供较高的安全性,能有效保护数据完整性和防篡改能力,并且能够抵抗一定的攻击手段,尽管性能较低,更适合对安全有高要求的应用场景。例如,SHA2、SHA3、SM3、RIPEMD-160、BLAKE2和SipHash等。

  2. 非加密哈希算法:该类算法的安全性较低,容易受到暴力破解和冲突攻击等威胁,尽管其性能较高,适用于对安全性要求不高的情况。例如,CRC32、MurMurHash3和SipHash等。

此外,还有一些特定的哈希算法,例如安全性更高的慢哈希算法

MD算法有多个版本,如MD2、MD4和MD5,其中MD5是最为常用的版本,它可以生成一个128位(16字节)的哈希值。从安全性上讲,MD5的安全性优于MD4,而MD4又优于MD2。尽管MD5是相对安全的版本,但它依然存在被破解的风险,攻击者可以通过暴力破解和使用彩虹表的方法,找到与原始数据相同的哈希值,进而破解数据。

为了增加破解的难度,可以使用加盐。加盐是指在密码的某个固定位置插入特定字符串,从而使得哈希结果与原始密码的哈希值不一致,称为“加盐”。然而,加盐并不意味着就绝对安全了,它只能增加破解的难度。实际上,MD5算法本身就存在弱碰撞(Collision)问题,即多个不同的输入可能产生相同的MD5值。因此,即使加盐,也不建议使用MD5加密密码。

尽管如此,网络上仍有大量教程采用MD5 + Salt的方式加密密码,值得关注和警惕。

为了提升安全性,建议使用安全性较高的加密哈希算法加盐(如SHA2、SHA3和SM3),并确保每个用户的Salt值不同(最好为不同用户的密码随机生成不同的Salt,确保Salt库和密码库分离),这样就能有效抵御利用彩虹表进行的批量破解。然而,这并不意味着完全没有破解风险,因为利用密码破解硬件,可以在短时间内进行数十亿次的哈希计算。

一种更安全的方案是采用密钥派生算法(KDF),它也被称为密码哈希算法。KDF相较于其他加密哈希算法,其计算速度较慢,并且设计上不易提升速度,因此被称为慢哈希算法。这种慢速是可以接受的,因为它主要是在用户登录时执行一次。

常见的KDF算法有(安全性依次递增):

  1. PBKDF2:通过对HMAC进行多次迭代增加破解难度,但该算法较老,已不再推荐使用。

  2. Bcrypt:基于Blowfish加密算法设计,安全性高于PBKDF2。虽然Bcrypt对内存需求较低,但不能抵挡密码破解硬件攻击。

  3. Scrypt:较PBKDF2和Bcrypt需要更多的内存,安全性更高,并能通过调整内存和CPU使用量来增加破解难度。

  4. Argon2:目前最强的密码哈希算法,赢得了2015年密码哈希竞赛,需大量内存使用,与Scrypt相比,能更有效抗击密码破解硬件。

Spring Security提供了上述KDF算法的实现(地址:https://docs.spring.io/spring-security/reference/features/authentication/password-storage.html):

![图片](data:image/svg+xml,%3C%3Fxml version='1.0' encoding='UTF-8'%3F%3E%3Csvg width='1px' height='1px' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Ctitle%3E%3C/title%3E%3Cg stroke='none' stroke-width='1' fill='none' fill-rule='evenodd' fill-opacity='0'%3E%3Cg transform='translate(-249.000000, -126.000000)' fill='%23FFFFFF'%3E%3Crect x='249' y='126' width='1' height='1'%3E%3C/rect%3E%3C/g%3E%3C/g%3E%3C/svg%3E)

对于大多数项目而言,Bcrypt通常已经足够使用,尽管其安全性不及Scrypt和Argon2,但综合性价比相对较高。

Bcrypt使用了salt和cost两种机制,有效地防止了彩虹表攻击和暴力破解攻击,从而确保密码安全。使用Bcrypt加密密码时,内置随机加盐过程,因此无需额外加盐。成本(cost)定义了哈希计算的复杂度,设置越高,计算所需的时间和资源越多,暴力破解攻击因此变得更加困难。实际项目中,可以根据系统性能与安全需求来调整cost的值。

Spring Security提供的BCryptPasswordEncoder工作因子的范围在4-31之间,默认值为10。

/**  
 * @param strength the log rounds to use, between 4 and 31  
 */  
public BCryptPasswordEncoder(int strength) {  
    this(strength, null);  
}