对于最新的稳定版本,请使用 Spring Security 7.0.4spring-doc.cadn.net.cn

Spring Security 加密模块

Spring Security 加密模块提供了对称加密、密钥生成和密码编码的支持。 该代码作为核心模块的一部分进行分发,但不依赖于任何其他 Spring Security(或 Spring)代码。spring-doc.cadn.net.cn

加密器

Encryptors 类提供了用于构建对称加密器的工厂方法。 该类允许您创建 BytesEncryptor 实例,以原始 byte[] 形式加密数据。 您还可以构建 TextEncryptor 实例来加密文本字符串。 加密器是线程安全的。spring-doc.cadn.net.cn

BytesEncryptorTextEncryptor 都是接口。BytesEncryptor 有多个实现。spring-doc.cadn.net.cn

字节加密器

你可以使用 Encryptors.stronger 工厂方法来构造一个 BytesEncryptorspring-doc.cadn.net.cn

字节加密器
Encryptors.stronger("password", "salt");
Encryptors.stronger("password", "salt")

stronger 加密方法通过使用带有伽罗瓦计数器模式(GCM)的 256 位 AES 加密来创建加密器。 它利用 PKCS #5 中的 PBKDF2(基于密码的密钥派生函数 #2)来派生密钥。 此方法需要 Java 6。 用于生成 SecretKey 的密码应妥善保管,不得共享。 盐值(salt)用于防止在加密数据泄露的情况下,针对密钥发起字典攻击。 此外,还会应用一个 16 字节的随机初始化向量(IV),以确保每条加密消息都是唯一的。spring-doc.cadn.net.cn

所提供的盐值应为十六进制编码的字符串形式,必须是随机的,并且长度至少为8字节。 你可以使用 KeyGenerator 来生成这样的盐值:spring-doc.cadn.net.cn

生成密钥
String salt = KeyGenerators.string().generateKey(); // generates a random 8-byte salt that is then hex-encoded
val salt = KeyGenerators.string().generateKey() // generates a random 8-byte salt that is then hex-encoded

你也可以使用 standard 加密方法,该方法采用密码块链接(CBC)模式下的 256 位 AES 加密。 此模式未经过认证,无法提供任何关于数据真实性的保证。 如需更安全的替代方案,请使用 Encryptors.strongerspring-doc.cadn.net.cn

文本加密器

你可以使用 Encryptors.text 工厂方法来构造一个标准的 TextEncryptor:spring-doc.cadn.net.cn

文本加密器
Encryptors.text("password", "salt");
Encryptors.text("password", "salt")

TextEncryptor 使用标准的 BytesEncryptor 来加密文本数据。 加密结果以十六进制编码的字符串形式返回,便于在文件系统或数据库中存储。spring-doc.cadn.net.cn

键生成器

KeyGenerators 类提供了多种便利的工厂方法,用于构建不同类型的密钥生成器。 通过使用此类,您可以创建一个 BytesKeyGenerator 来生成 byte[] 密钥。 您还可以构建一个 StringKeyGenerator 来生成字符串密钥。 KeyGenerators 是一个线程安全的类。spring-doc.cadn.net.cn

字节密钥生成器

你可以使用 KeyGenerators.secureRandom 工厂方法来生成一个由 BytesKeyGenerator 实例支持的 SecureRandomspring-doc.cadn.net.cn

字节密钥生成器
BytesKeyGenerator generator = KeyGenerators.secureRandom();
byte[] key = generator.generateKey();
val generator = KeyGenerators.secureRandom()
val key = generator.generateKey()

默认密钥长度为 8 字节。 KeyGenerators.secureRandom 的一个变体提供了对密钥长度的控制:spring-doc.cadn.net.cn

KeyGenerators.secureRandom
KeyGenerators.secureRandom(16);
KeyGenerators.secureRandom(16)

使用 KeyGenerators.shared 工厂方法来构造一个 BytesKeyGenerator,该生成器在每次调用时始终返回相同的密钥:spring-doc.cadn.net.cn

KeyGenerators.shared
KeyGenerators.shared(16);
KeyGenerators.shared(16)

字符串键生成器

你可以使用 KeyGenerators.string 工厂方法来构造一个 8 字节、基于 SecureRandomKeyGenerator,它会将每个密钥以十六进制编码为 Stringspring-doc.cadn.net.cn

字符串键生成器
KeyGenerators.string();
KeyGenerators.string()

密码加密

spring-security-crypto 模块的 password 包提供了对密码编码的支持。
PasswordEncoder 是核心的服务接口,其签名如下:spring-doc.cadn.net.cn

public interface PasswordEncoder {
	String encode(CharSequence rawPassword);

	boolean matches(CharSequence rawPassword, String encodedPassword);

	default boolean upgradeEncoding(String encodedPassword) {
		return false;
	}
}

如果 matches 经过编码后等于 rawPassword,则 encodedPassword 方法返回 true。 该方法旨在支持基于密码的身份验证方案。spring-doc.cadn.net.cn

BCryptPasswordEncoder 的实现使用了广泛支持的 “bcrypt” 算法来对密码进行哈希。 Bcrypt 使用一个随机的 16 字节盐值,并且是一种故意设计得较慢的算法,以阻碍密码破解。 你可以通过 strength 参数来调整其计算强度,该参数的取值范围为 4 到 31。 该值越高,计算哈希所需的工作量就越大。 默认值为 10。 你可以在已部署的系统中更改此值,而不会影响现有的密码,因为该值也会被存储在编码后的哈希中。 以下示例使用了 BCryptPasswordEncoderspring-doc.cadn.net.cn

BCryptPasswordEncoder
// Create an encoder with strength 16
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(16);
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
// Create an encoder with strength 16
val encoder = BCryptPasswordEncoder(16)
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))

Pbkdf2PasswordEncoder 实现使用 PBKDF2 算法对密码进行哈希。 为了防止密码被破解,PBKDF2 是一种刻意设计得较慢的算法,应调整其参数,使其在您的系统上验证一个密码大约耗时 0.5 秒。 以下系统使用了 Pbkdf2PasswordEncoderspring-doc.cadn.net.cn

Pbkdf2PasswordEncoder
// Create an encoder with all the defaults
Pbkdf2PasswordEncoder encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8();
String result = encoder.encode("myPassword");
assertTrue(encoder.matches("myPassword", result));
// Create an encoder with all the defaults
val encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8()
val result: String = encoder.encode("myPassword")
assertTrue(encoder.matches("myPassword", result))