Encryption (CSFLE)

客户端加密是一项可在数据发送至 MongoDB 之前对数据进行加密的特性。我们建议您熟悉这些概念,理想情况下可以从 MongoDB Documentation 了解有关其功能和限制的更多信息,然后再通过 Spring Data 应用加密。

请务必设置驱动程序`com.mongodb.AutoEncryptionSettings`以使用客户端加密。MongoDB不支持对所有字段类型进行加密。特定的数据类型需要确定性加密,以保留相等比较功能。

Automatic Encryption

MongoDB 支持 Client-Side Field Level Encryption,使用 MongoDB 驱动程序及其自动加密特性即可实现。自动加密要求 JSON Schema,允许执行加密的读写操作,而无需提供明确的加密/解密步骤。

有关定义包含加密信息的 JSON 架构的详细信息,请参阅 JSON Schema部分。

要使用`MongoJsonSchema`,它需要与`AutoEncryptionSettings`结合使用,例如可以通过`MongoClientSettingsBuilderCustomizer`来实现。

@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);
    };
}

Explicit Encryption

显式加密使用 MongoDB 驱动的加密库(org.mongodb:mongodb-crypt)来执行加密和解密任务。@ExplicitEncrypted 注解是为 JSON Schema creation 使用的 @Encrypted 注解和 Property Converter 的组合。换句话说,@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 内的 Address#street 字段,则需要使用 @ExplicitEncrypted 对其进行注释。
3 Collection 型字段被加密为单个值,而不是每项一个值。
4 Map 型字段被加密为单个值,而不是键/值项。

客户端字段级别加密允许您选择确定性算法和随机算法。根据 chosen algorithmdifferent operations 可能受支持。若要选择某个算法,请使用 @ExplicitEncrypted(algorithm),有关算法常量,请参阅 EncryptionAlgorithms。有关算法及其用法,请阅读 Encryption Types 手册。

为了执行实际加密,我们需要一个数据加密密钥 (DEK)。有关如何设置密钥管理和创建数据加密密钥的更多信息,请参阅 MongoDB Documentation。可以通过其 id 或已定义的 alternative name 直接引用 DEK。@EncryptedField 注解只允许通过别名引用 DEK。可以为任何 DEK 提供 EncryptionKeyResolver(我们稍后讨论)。

Example 1. Reference the Data Encryption Key
@EncryptedField(algorithm=…, altKeyName = "secret-key") 1
String ssn;
@EncryptedField(algorithm=…, altKeyName = "/name")      2
String ssn;
1 使用以备用名称 secret-key 存储的 DEK。
2 使用字段引用,该引用将读取实际字段值并使用该值进行键查找。始终需要提供完整文档才能保存操作。字段不能用于查询/聚合。

默认情况下,@ExplicitEncrypted(value=…) 属性引用 MongoEncryptionConverter。可以更改默认实现,并通过提供相应的类型引用,用任何 PropertyValueConverter 实现替换它。有关自定义 PropertyValueConverters 和所需配置的更多信息,请参阅 Property Converters - Mapping specific fields 部分。

MongoEncryptionConverter Setup

MongoEncryptionConverter 的转换器设置需要几个步骤,因为涉及多个组件。Bean 设置包括以下内容:

  1. The ClientEncryption engine

  2. 使用 ClientEncryptionEncryptionKeyResolver 配置的 MongoEncryptionConverter 实例。

  3. 一个使用已注册 MongoEncryptionConverter bean 的 PropertyValueConverterFactory

使用带注释密钥解析的一个副作用是 @ExplicitEncrypted 注释不需要指定 alt 键名称。EncryptionKeyResolver 使用 EncryptionContext 提供对属性的访问,允许动态 DEK 解析。

Example 2. Sample MongoEncryptionConverter Configuration
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 使用 com.mongodb.client.vault.ClientEncryption 设置一个 Encryption 引擎。该实例是有状态的,并且在使用后必须关闭。Spring 会处理这件事,因为 ClientEncryptionCloseable
2 EncryptionKeyResolver`基于注释设置以从注释中确定 `EncryptionKey
3 Create the MongoEncryptionConverter.
4 启用从 BeanFactory 中进行 PropertyValueConverter 查找。