Encryption (CSFLE)

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

Client Side Encryption is a feature that encrypts data in your application before it is sent to MongoDB. We recommend you get familiar with the concepts, ideally from the MongoDB Documentation to learn more about its capabilities and restrictions before you continue applying Encryption through Spring Data.

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

Make sure to set the drivers com.mongodb.AutoEncryptionSettings to use client-side encryption. MongoDB does not support encryption for all field types. Specific data types require deterministic encryption to preserve equality comparison functionality.

Automatic Encryption

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

MongoDB supports Client-Side Field Level Encryption out of the box using the MongoDB driver with its Automatic Encryption feature. Automatic Encryption requires a JSON Schema that allows to perform encrypted read and write operations without the need to provide an explicit en-/decryption step.

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

Please refer to the JSON Schema section for more information on defining a JSON Schema that holds encryption information.

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

To make use of a the MongoJsonSchema it needs to be combined with AutoEncryptionSettings which can be done eg. via a 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 使用现有的构建模块将它们结合起来以简化显式加密支持。

Explicit encryption uses the MongoDB driver’s encryption library (org.mongodb:mongodb-crypt) to perform encryption and decryption tasks. The @ExplicitEncrypted annotation is a combination of the @Encrypted annotation used for JSON Schema creation and a Property Converter. In other words, @ExplicitEncrypted uses existing building blocks to combine them for simplified explicit encryption support.

用`@ExplicitEncrypted`注释的字段始终被整体加密。考虑以下示例:

Fields annotated with @ExplicitEncrypted are always encrypted as whole. Consider the following example:

@ExplicitEncrypted(…)
String simpleValue;        1

@ExplicitEncrypted(…)
Address address;           2

@ExplicitEncrypted(…)
List<...> list;            3

@ExplicitEncrypted(…)
Map<..., ...> mapOfString; 4
1 Encrypts the value of the simple type such as a String if not null.
2 Encrypts the entire Address object and all its nested fields as Document. To only encrypt parts of the Address, like Address#street the street field within Address needs to be annotated with @ExplicitEncrypted.
3 Collection-like fields are encrypted as single value and not per entry.
4 Map-like fields are encrypted as single value and not as a key/value entry.

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

Client-Side Field Level Encryption allows you to choose between a deterministic and a randomized algorithm. Depending on the chosen algorithm, different operations may be supported. To pick a certain algorithm use @ExplicitEncrypted(algorithm), see EncryptionAlgorithms for algorithm constants. Please read the Encryption Types manual for more information on algorithms and their usage.

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

To perform the actual encryption we require a Data Encryption Key (DEK). Please refer to the MongoDB Documentation for more information on how to set up key management and create a Data Encryption Key. The DEK can be referenced directly via its id or a defined alternative name. The @EncryptedField annotation only allows referencing a DEK via an alternative name. It is possible to provide an EncryptionKeyResolver, which will be discussed later, to any DEK.

Example 1. Reference the Data Encryption Key
@EncryptedField(algorithm=…, altKeyName = "secret-key") 1
String ssn;
@EncryptedField(algorithm=…, altKeyName = "/name")      2
String ssn;
1 Use the DEK stored with the alternative name secret-key.
2 Uses a field reference that will read the actual field value and use that for key lookup. Always requires the full document to be present for save operations. Fields cannot be used in queries/aggregations.

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

By default, the @ExplicitEncrypted(value=…) attribute references a MongoEncryptionConverter. It is possible to change the default implementation and exchange it with any PropertyValueConverter implementation by providing the according type reference. To learn more about custom PropertyValueConverters and the required configuration, please refer to the Property Converters - Mapping specific fields section.

MongoEncryptionConverter Setup

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

The converter setup for MongoEncryptionConverter requires a few steps as several components are involved. The bean setup consists of the following:

  1. The ClientEncryption engine

  2. A MongoEncryptionConverter instance configured with ClientEncryption and a EncryptionKeyResolver.

  3. A PropertyValueConverterFactory that uses the registered MongoEncryptionConverter bean.

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

A side effect of using annotated key resolution is that the @ExplicitEncrypted annotation does not need to specify an alt key name. The EncryptionKeyResolver uses an EncryptionContext providing access to the property allowing for dynamic DEK resolution.

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 Set up a Encryption engine using com.mongodb.client.vault.ClientEncryption. The instance is stateful and must be closed after usage. Spring takes care of this because ClientEncryption is Closeable.
2 Set up an annotation-based EncryptionKeyResolver to determine the EncryptionKey from annotations.
3 Create the MongoEncryptionConverter.
4 Enable for a PropertyValueConverter lookup from the BeanFactory.