加密 (CSFLE)

客户端加密是在数据发送到 MongoDB 之前在您的应用程序中对数据进行加密的功能。我们建议您熟悉这些概念,最好是从 MongoDB 文档 中学习更多关于其功能和限制的信息,然后再继续通过 Spring Data 应用加密。

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

自动加密

MongoDB 使用 MongoDB 驱动程序及其自动加密功能开箱即用地支持 客户端侧字段级加密。自动加密需要一个 JSON 架构,该架构允许执行加密的读写操作,而无需提供明确的加密/解密步骤。

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

为了使用 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);
    };
}

显式加密

显式加密使用 MongoDB 驱动程序的加密库 (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,则需要在 Address 中的 street 字段上添加 @ExplicitEncrypted 注解。
3 Collection 类字段被加密为单个值,而不是每个条目。
4 Map 类字段被加密为单个值,而不是作为键/值条目。

客户端字段级加密允许您在确定性算法和随机算法之间进行选择。根据 所选算法,可能支持 不同的操作。要选择特定算法,请使用 @ExplicitEncrypted(algorithm),请参见 EncryptionAlgorithms 获取算法常量。有关算法及其用法的更多信息,请阅读 加密类型 手册。

要执行实际加密,我们需要一个数据加密密钥 (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 使用字段引用,该引用将读取实际字段值并将其用于密钥查找。始终需要完整的文档才能执行保存操作。字段不能在查询/聚合中使用。

默认情况下,@ExplicitEncrypted(value=…) 属性引用 MongoEncryptionConverter。可以通过提供相应的类型引用来更改默认实现并将其替换为任何 PropertyValueConverter 实现。要了解有关自定义 PropertyValueConverters 和所需配置的更多信息,请参阅 属性转换器 - 映射特定字段 部分。

MongoEncryptionConverter 设置

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

  1. ClientEncryption 引擎

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

  3. 使用已注册的 MongoEncryptionConverter Bean 的 PropertyValueConverterFactory

使用带注释的密钥解析的副作用是,@ExplicitEncrypted 注释不需要指定备用密钥名称。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 使用 com.mongodb.client.vault.ClientEncryption 设置 Encryption 引擎。该实例是有状态的,必须在使用后关闭。Spring 会处理此操作,因为 ClientEncryptionCloseable
2 设置基于注释的 EncryptionKeyResolver 以从注释中确定 EncryptionKey
3 创建 MongoEncryptionConverter
4 BeanFactory 中的 PropertyValueConverter 查找启用。