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

Spring Security 加密模块

介绍

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

加密器

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

字节加密器

使用Encryptors.strongerfactory 方法来构造 BytesEncrypter:spring-doc.cadn.net.cn

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

“更强”的加密方法使用 256 位 AES 加密创建加密器,其中 伽罗瓦计数器模式 (GCM)。 它使用 PKCS #5 的 PBKDF2(基于密码的密钥派生函数 #2)派生密钥。 此方法需要 Java 6。 用于生成密钥的密码应保存在安全的地方,不得共享。 该盐用于防止在加密数据泄露时对密钥进行字典攻击。 还应用了 16 字节的随机初始化向量,因此每条加密消息都是唯一的。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.stronger.spring-doc.cadn.net.cn

文本加密器

使用 Encryptors.text 工厂方法构造标准 TextEncrypter:spring-doc.cadn.net.cn

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

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

使用 Encryptors.queryableText 工厂方法构造“可查询”的 TextEncrypter:spring-doc.cadn.net.cn

可查询的 TextEncryptor
Encryptors.queryableText("password", "salt");
Encryptors.queryableText("password", "salt")

可查询的 TextEncryptor 和标准 TextEncryptor 之间的区别与初始化向量 (iv) 处理有关。 可查询的 TextEncryptor#encrypt作中使用的 iv 是共享的或常量的,并且不是随机生成的。 这意味着多次加密的相同文本将始终产生相同的加密结果。 这不太安全,但对于需要查询的加密数据来说是必要的。 可查询加密文本的一个示例是 OAuth apiKey。spring-doc.cadn.net.cn

密钥生成器

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

字节密钥生成器

使用 KeyGenerators.secureRandom 工厂方法生成由 SecureRandom 实例支持的 BytesKeyGenerator:spring-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,该 BytesKeyGenerator 在每次调用时始终返回相同的键:spring-doc.cadn.net.cn

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

字符串键生成器

使用 KeyGenerators.string 工厂方法构造一个 8 字节的 SecureRandom KeyGenerator,该 KeyGenerator 将每个键十六进制编码为 String:spring-doc.cadn.net.cn

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

密码编码

spring-security-crypto模块的密码包提供了对密码编码的支持。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;
	}
}

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

BCryptPasswordEncoder实现使用广泛支持的“bcrypt”算法来哈希密码。 Bcrypt 使用随机的 16 字节盐值,并且是一种故意缓慢的算法,以阻止密码破解者。 它所做的功量可以使用“强度”参数进行调整,该参数的值从 4 到 31。 值越高,计算哈希值需要做的工作就越多。 默认值为 10。 您可以在部署的系统中更改此值,而不会影响现有密码,因为该值也存储在编码的哈希中。spring-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 是一种故意缓慢的算法,应调整为大约需要 5 秒来验证系统上的密码。spring-doc.cadn.net.cn

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