密码如何安全保存?五种方式送上
1、使用 BCrypt 进行密码加密
核心特性:
- 内建加盐机制,有效防止彩虹表攻击;
- 可以设置加密强度;
- 哈希结果长度固定(60 字符),便于存储。
依赖配置(如未引入 Spring Security):
<!-- /src/main/resources/pom.xml -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
加密与验证实现:
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordUtils {
private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
public static String encode(String rawPassword) {
return encoder.encode(rawPassword);
}
public static boolean matches(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
测试代码:
public static void main(String[] args) {
String raw = "mypassword";
String encoded = PasswordUtils.encode(raw);
System.out.println("BCrypt加密后: " + encoded);
System.out.println("是否匹配: " + PasswordUtils.matches(raw, encoded));
}
优劣分析:
- ✅ 安全性好,使用方便;
- ❌ 相比其他算法,加密速度稍慢。
2、借助 PBKDF2 增强密码存储
PBKDF2 通过多轮迭代和盐值计算,进一步加大破解成本。
依赖保持一致:
<!-- /src/main/resources/pom.xml -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
编码实现:
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
public class PasswordUtils {
private static final Pbkdf2PasswordEncoder encoder = new Pbkdf2PasswordEncoder();
public static String encode(String rawPassword) {
return encoder.encode(rawPassword);
}
public static boolean matches(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
运行测试:
public static void main(String[] args) {
String password = "mypassword";
String hash = PasswordUtils.encode(password);
System.out.println("PBKDF2加密后: " + hash);
System.out.println("匹配结果: " + PasswordUtils.matches(password, hash));
}
优劣势:
- ✅ 兼容性好,支持迭代配置;
- ❌ 设置相对复杂。
3、使用 Argon2 保护密码(现代首选)
背景说明:Argon2 是密码哈希竞赛的冠军,专为现代系统安全设计,是目前公认的最强哈希算法之一。
引入依赖:
<!-- /src/main/resources/pom.xml -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
</dependency>
核心代码:
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
public class PasswordUtils {
private static final Argon2PasswordEncoder encoder = new Argon2PasswordEncoder();
public static String encode(String rawPassword) {
return encoder.encode(rawPassword);
}
public static boolean matches(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
控制台输出测试:
public static void main(String[] args) {
String pwd = "mypassword";
String encoded = PasswordUtils.encode(pwd);
System.out.println("Argon2加密后:" + encoded);
System.out.println("匹配结果:" + PasswordUtils.matches(pwd, encoded));
}
分析:
- ✅ 安全性极高,能抵抗 GPU 暴力破解;
- ❌ 性能消耗大,部分旧设备不支持。
4、采用 SCrypt:内存型算法对抗硬件攻击
SCrypt 的设计重点是通过占用大量内存来防御并行攻击,尤其对抗显卡加速的暴力尝试非常有效。
代码实现:
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
public class PasswordUtils {
private static final SCryptPasswordEncoder encoder = new SCryptPasswordEncoder();
public static String encode(String rawPassword) {
return encoder.encode(rawPassword);
}
public static boolean matches(String rawPassword, String encodedPassword) {
return encoder.matches(rawPassword, encodedPassword);
}
}
验证示例:
public static void main(String[] args) {
String origin = "mypassword";
String hash = PasswordUtils.encode(origin);
System.out.println("SCrypt加密结果:" + hash);
System.out.println("匹配情况:" + PasswordUtils.matches(origin, hash));
}
优缺点:
- ✅ 超强抗攻击能力;
- ❌ 加密成本高,不适合性能敏感的系统。
5、手动实现 SHA-256 + 随机盐值
虽然 SHA-256 本身不够安全,但通过加入 salt 和迭代处理可以提升保护能力。
手工实现加密逻辑:
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
public class PasswordUtils {
public static String generateSalt() {
byte[] salt = new byte[16];
new SecureRandom().nextBytes(salt);
return Base64.getEncoder().encodeToString(salt);
}
public static String hashPassword(String password, String salt) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] result = digest.digest((salt + password).getBytes());
for (int i = 0; i < 1000; i++) {
result = digest.digest(result);
}
return Base64.getEncoder().encodeToString(result);
} catch (Exception e) {
throw new RuntimeException("哈希失败", e);
}
}
public static boolean matches(String rawPassword, String salt, String hashedPassword) {
return hashPassword(rawPassword, salt).equals(hashedPassword);
}
}
测试程序:
public static void main(String[] args) {
String pwd = "mypassword";
String salt = PasswordUtils.generateSalt();
String hashed = PasswordUtils.hashPassword(pwd, salt);
System.out.println("生成盐值: " + salt);
System.out.println("SHA-256+Salt 加密: " + hashed);
System.out.println("匹配情况: " + PasswordUtils.matches(pwd, salt, hashed));
}
总结分析:
- ✅ 实现简单,适合与旧系统集成;
- ❌ 不抗彩虹表攻击,必须管理好盐值。
对比总结
| 方法 | 安全性 | 性能 | 适用情况 |
|---|---|---|---|
| BCrypt | 高 | 中 | 推荐用于通用系统 |
| PBKDF2 | 高 | 中 | 适用于企业级复杂环境 |
| Argon2 | 极高 | 较低 | 对安全性要求极高的应用 |
| SCrypt | 极高 | 较低 | 抵御硬件加速暴力破解 |
| SHA-256 + Salt | 中 | 高 | 安全性可控的内网系统或老旧系统 |
最佳实践建议
- ✅ 普通场景首选:BCrypt 是性价比最优的方案;
- 🔒 对安全性要求极致:请选择 Argon2 或 SCrypt;
- 🧪 兼容旧系统:可以考虑 SHA-256 + salt,但必须加上防御机制。
无需再存明文密码,让你的系统从此具备防弹级的安全加密体系!