@[TOC](【Spring连载】使用Spring Data访问 mongodb(十一)----加密Encryption (CSFLE))
客户端加密(Client-Side Field Level Encryption)是一种在将数据发送到MongoDB之前对应用程序中的数据进行加密的功能。我们建议你熟悉这些概念,最好是从MongoDB文档中了解更多关于其功能和限制的信息,然后再继续通过Spring Data应用加密。
确保将驱动程序“***.mongodb.AutoEncryptionSettings”设置为使用客户端加密。MongoDB不支持对所有字段类型进行加密。特定的数据类型需要确定性加密以保留相等性比较功能。
一、自动加密
MongoDB使用MongoDB driver及其自动加密功能,支持开箱即用的客户端字段级加密。自动加密需要一个JSON Schema,该Schema允许执行加密的读写操作,而无需提供显式的加密/解密步骤。
有关定义包含加密信息的JSON Schema的更多信息,请参阅JSON Schema部分。
要使用MongoJsonSchema,它需要与AutoEncryptionSettings相结合,例如可以通过MongoClientSettingsBuilderCustomizer来完成。
java">@Bean
MongoClientSettingsBuilderCustomizer customizer(MappingContext mappingContext) {
return (builder) -> {
// ... keyVaultCollection, kmsProvider, ...
MongoJsonSchemaCreator schemaCreator = MongoJsonSchemaCreator.create(mappingContext);
MongoJsonSchema patientSchema = schemaCreator
.filter(MongoJsonSchemaCreator.encryptedOnly())
.createSchemaFor(Patient.class);
AutoEncryptionSettings autoEncryptionSettings = AutoEncryptionSettings.builder()
.keyVaultNamespace(keyVaultCollection)
.kmsProviders(kmsProviders)
.extraOptions(extraOpts)
.schemaMap(Collections.singletonMap("db.patient", patientSchema.schemaDocument().toBsonDocument()))
.build();
builder.autoEncryptionSettings(autoEncryptionSettings);
};
}
二、显式加密
显式加密使用MongoDB driver的加密库(org.mongodb:mongodb-crypt)来执行加密和解密任务。@ExplicitEncrypted注解是用于创建 JSON Schema的@Encrypted注解和属性转换器的组合。换句话说,@ExplicitEncrypted使用现有的构建块来组合它们,以简化显式加密支持。
使用@ExplicitEncrypted注解的字段始终作为整体进行加密。参见以下示例:
@ExplicitEncrypted(…)
String simpleValue; --------1
@ExplicitEncrypted(…)
Address address; --------2
@ExplicitEncrypted(…)
List<...> list; --------3
@ExplicitEncrypted(…)
Map<..., ...> mapOfString;--------4
1. 如果不是null,则加密简单类型(如String)的值。
2. 将整个Address对象及其所有嵌套字段加密为Document。要只加密部分Address,如Address#street,地址中的街道字段需要用@ExplicitEncrypted进行注释。
3. 类似集合的字段被加密为单个值,而不是每个条目。
4. 类似Map的字段被加密为单个值,而不是key/value条目。
根据加密算法的不同,MongoDB使用其Queryable Encryption功能支持对加密字段的某些操作。要选择某个算法,请使用@ExplicitEncrypted(algorithm),有关算法常数请参阅EncryptionAlgorithms。有关算法及其用法的更多信息,请阅读加密类型手册。
为了执行实际加密,我们需要一个数据加密密钥(Data Encryption Key,DEK)。有关如何设置密钥管理和创建数据加密密钥的更多信息,请参阅MongoDB文档。DEK可以通过其id或定义的替代名称直接引用。@EncryptedField注解仅允许通过替代名称引用DEK。可以向任何DEK提供EncryptionKeyResolver。
例1:引用数据加密密钥
@EncryptedField(algorithm=…, altKeyName = "secret-key") --------1
String ssn;
@EncryptedField(algorithm=…, altKeyName = "/name") --------2
String ssn;
1. 使用用了备选名称secret-key存储的DEK。
2. 使用将读取实际字段值并将其用于key查找的字段引用。总是要求保存操作提供完整的document。字段不能在查询/聚合中使用。
默认情况下,@ExplicitEncrypted(value=…)属性引用MongoEncryptionConverter。可以更改默认实现,并通过提供相应的类型引用与任何PropertyValueConverter实现进行交换。要了解有关自定义PropertyValueConverters和所需配置的更多信息,请参阅“属性转换器-映射特定字段”部分。
2.1 MongoEncryptionConverter设置
MongoEncryptionConverter的转换器设置需要几个步骤,因为需要几个组件。bean设置包括以下内容:
- ClientEncryption引擎
- 配置了ClientEncryption和EncryptionKeyResolver的MongoEncryptionConverter实例。
- 使用注册的MongoEncryptionConverter bean的PropertyValueConverterFactory。
使用带注解的key解析的一个效果是@ExplicitEncrypted注解不需要指定alt key名称。EncryptionKeyResolver使用EncryptionContext来访问允许动态DEK解析的属性。
例2:MongoEncryptionConverter配置示例
class Config extends AbstractMongoClientConfiguration {
@Autowired ApplicationContext appContext;
@Bean
ClientEncryption clientEncryption() { --------1
ClientEncryptionSettings encryptionSettings = ClientEncryptionSettings.builder();
// …
return ClientEncryptions.create(encryptionSettings);
}
@Bean
MongoEncryptionConverter encryptingConverter(ClientEncryption clientEncryption) {
Encryption<BsonValue, BsonBinary> encryption = MongoClientEncryption.just(clientEncryption);
EncryptionKeyResolver keyResolver = EncryptionKeyResolver.annotated((ctx) -> …); --------2
return new MongoEncryptionConverter(encryption, keyResolver); --------3
}
@Override
protected void configureConverters(MongoConverterConfigurationAdapter adapter) {
adapter
.registerPropertyValueConverterFactory(PropertyValueConverterFactory.beanFactoryAware(appContext)); --------4
}
}
1. 使用***.mongodb.client.vault.ClientEncryption设置加密引擎。实例是有状态的,使用后必须关闭。Spring负责处理这一问题,因为ClientEncryption是Closeable。
2. 设置基于注解的EncryptionKeyResolver以根据注解确定EncryptionKey。
3. 创建MongoEncryptionConverter。
4. 启用以从BeanFactory进行PropertyValueConverter查找。