Spring Boot 实现密码加密存储的五种硬核方式

277 阅读3分钟

密码如何安全保存?五种方式送上

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,但必须加上防御机制。

无需再存明文密码,让你的系统从此具备防弹级的安全加密体系!