此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Data MongoDB 4.5.2spring-doc.cadn.net.cn

加密

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

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

客户端字段级加密 (CSFLE)

选择 CSFLE 为您提供了充分的灵活性,并允许您对单个字段使用不同的键,例如。在每个租户一个密钥方案中。
在继续阅读之前,请务必查阅 MongoDB CSFLE 文档spring-doc.cadn.net.cn

自动加密 (CSFLE)

MongoDB 使用具有自动加密功能的 MongoDB 驱动程序支持开箱即用的客户端字段级加密。 自动加密需要一个 JSON 模式,该模式允许执行加密的读写作,而无需提供显式的 en-/decryption 步骤。spring-doc.cadn.net.cn

请参阅 JSON Schema 部分,了解有关定义包含加密信息的 JSON Schema 的更多信息。spring-doc.cadn.net.cn

要使用MongoJsonSchema它需要与AutoEncryptionSettings这可以做到,例如。通过MongoClientSettingsBuilderCustomizer.spring-doc.cadn.net.cn

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

显式加密 (CSFLE)

显式加密使用 MongoDB 驱动程序的加密库 (org.mongodb:mongodb-crypt) 执行加密和解密任务。 这@ExplicitEncrypted注释是@Encrypted用于 JSON 模式创建属性转换器的注释。 换句话说,@ExplicitEncrypted使用现有构建块将它们组合起来,以简化显式加密支持。spring-doc.cadn.net.cn

@ExplicitEncrypted始终作为一个整体进行加密。 请考虑以下示例:spring-doc.cadn.net.cn

@ExplicitEncrypted(…)
String simpleValue;        (1)

@ExplicitEncrypted(…)
Address address;           (2)

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

@ExplicitEncrypted(…)
Map<..., ...> mapOfString; (4)
1 加密简单类型的值,例如String如果没有null.
2 加密整个Address对象及其所有嵌套字段作为Document. 要仅加密部分Address喜欢Address#streetstreet字段Address需要用@ExplicitEncrypted.
3 Collection-like 字段被加密为单个值,而不是每个条目。
4 Map-like 字段被加密为单个值,而不是键/值条目。

客户端字段级加密允许您在确定性算法和随机算法之间进行选择。根据所选算法,可能支持不同的作。 要选择某种算法,请使用@ExplicitEncrypted(algorithm)EncryptionAlgorithms对于算法常量。 请阅读加密类型手册,了解有关算法及其用法的更多信息。spring-doc.cadn.net.cn

要执行实际的加密,我们需要数据加密密钥 (DEK)。 有关如何设置密钥管理和创建数据加密密钥的更多信息,请参阅 MongoDB 文档。 DEK 可以通过其id或定义的替代名称。 这@EncryptedField注释仅允许通过备用名称引用 DEK。 可以提供EncryptionKeyResolver,稍后将讨论,对任何 DEK.spring-doc.cadn.net.cn

示例 1.引用数据加密密钥
@EncryptedField(algorithm=…, altKeyName = "secret-key") (1)
String ssn;
@EncryptedField(algorithm=…, altKeyName = "/name")      (2)
String ssn;
1 使用使用备用名称存储的 DEKsecret-key.
2 使用字段引用来读取实际字段值并将其用于键查找。 始终要求存在完整的文档才能进行保存作。 字段不能用于查询/聚合。

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

可查询加密 (QE)

选择 QE 使您能够对加密字段运行不同类型的查询,例如范围相等性。
在继续阅读之前,请务必查阅 MongoDB QE 文档,以了解有关 QE 功能和限制的更多信息。spring-doc.cadn.net.cn

集合设置

可查询加密需要预先声明针对加密字段的实际查询中允许的某些方面。 该信息涵盖正在使用的算法以及允许的查询类型及其属性,并且必须在创建集合时提供。spring-doc.cadn.net.cn

MongoOperations#createCollection(…​)可用于对使用 QE 的集合进行初始设置。 通过 Spring Data 的 QE 配置使用与 CSFLE 相同的构建块(JSON Schema 创建),将 schema/properties 转换为 MongoDB 所需的配置格式。spring-doc.cadn.net.cn

您可以手动或以派生方式配置可查询加密:spring-doc.cadn.net.cn

手动设置使您可以完全控制加密字段的声明方式和集合的创建方式。 当需要显式管理数据密钥、加密算法和字段映射时,它非常有用。spring-doc.cadn.net.cn

*派生设置spring-doc.cadn.net.cn

派生设置依赖于域模型中的注释,并从中自动生成所需的加密字段配置。 这更简单,建议用于数据模型已经注释的典型 Spring 应用程序。spring-doc.cadn.net.cn

BsonBinary pinDK = clientEncryption.createDataKey("local", new com.mongodb.client.model.vault.DataKeyOptions());
BsonBinary ssnDK = clientEncryption.createDataKey("local", new com.mongodb.client.model.vault.DataKeyOptions());
BsonBinary ageDK = clientEncryption.createDataKey("local", new com.mongodb.client.model.vault.DataKeyOptions());
BsonBinary signDK = clientEncryption.createDataKey("local", new com.mongodb.client.model.vault.DataKeyOptions());

CollectionOptions collectionOptions = CollectionOptions.encryptedCollection(options -> options
    .encrypted(string("pin"), pinDK)
    .queryable(encrypted(string("ssn")).algorithm("Indexed").keyId(ssnDK.asUuid()), equality().contention(0))
    .queryable(encrypted(int32("age")).algorithm("Range").keyId(ageDK.asUuid()), range().contention(8).min(0).max(150))
    .queryable(encrypted(int64("address.sign")).algorithm("Range").keyId(signDK.asUuid()), range().contention(2).min(-10L).max(10L))
);

mongoTemplate.createCollection(Patient.class, collectionOptions); (1)
1 使用模板创建集合可能会阻止捕获生成的 keyId。在这种情况下,将Document从选项中,使用createEncryptedCollection(…​)方法。
class Patient {

    @Id String id;        (1)

    Address address;      (1)

    @Encrypted(algorithm = "Unindexed")
    String pin;           (2)

    @Encrypted(algorithm = "Indexed")
    @Queryable(queryType = "equality", contentionFactor = 0)
    String ssn;           (3)

    @RangeEncrypted(contentionFactor = 8, rangeOptions = "{ 'min' : 0, 'max' : 150 }")
    Integer age;          (4)

    @RangeEncrypted(contentionFactor = 0L,
        rangeOptions = "{\"min\": {\"$numberDouble\": \"0.3\"}, \"max\": {\"$numberDouble\": \"2.5\"}, \"precision\": 2 }")
    double height;        (5)
}

MongoJsonSchema patientSchema = MongoJsonSchemaCreator.create(mappingContext)
    .filter(MongoJsonSchemaCreator.encryptedOnly())
    .createSchemaFor(Patient.class);

Document encryptedFields = CollectionOptions.encryptedCollection(patientSchema)
        .getEncryptedFieldsOptions()
        .map(CollectionOptions.EncryptedFieldsOptions::toDocument)
        .orElseThrow();

template.execute(db -> clientEncryption.createEncryptedCollection(db, template.getCollectionName(Patient.class), new CreateCollectionOptions()
        .encryptedFields(encryptedFields), new CreateEncryptedCollectionParams("local"))); (1)
1 idaddress未加密。 这些字段可以正常查询。
2 pin已加密,但不支持查询。
3 ssn是加密的,允许相等查询。
4 age是加密的,并允许在0150.
5 height是加密的,并允许在0.32.5.

Queryable注释允许为加密字段定义允许的查询类型。@RangeEncrypted@Encrypted@Queryable对于允许的领域range查询。 可以从提供的注释中创建自定义注释。spring-doc.cadn.net.cn

{
    name: 'patient',
    type: 'collection',
    options: {
      encryptedFields: {
        escCollection: 'enxcol_.test.esc',
        ecocCollection: 'enxcol_.test.ecoc',
        fields: [
          {
            keyId: ...,
            path: 'ssn',
            bsonType: 'string',
            queries: [ { queryType: 'equality', contention: Long('0') } ]
          },
          {
            keyId: ...,
            path: 'age',
            bsonType: 'int',
            queries: [ { queryType: 'range', contention: Long('8'), min: 0, max: 150 } ]
          },
          {
            keyId: ...,
            path: 'pin',
            bsonType: 'string'
          },
          {
            keyId: ...,
            path: 'address.sign',
            bsonType: 'long',
            queries: [ { queryType: 'range', contention: Long('2'), min: Long('-10'), max: Long('10') } ]
          }
        ]
      }
    }
}

自动加密 (QE)

MongoDB 使用具有自动加密功能的 MongoDB 驱动程序支持开箱即用的可查询加密。 自动加密需要一个 JSON 模式,该模式允许执行加密的读写作,而无需提供显式的 en-/decryption 步骤。spring-doc.cadn.net.cn

您需要做的就是根据 MongoDB 文档创建集合。 您可以利用技术来创建上一节中概述的所需配置。spring-doc.cadn.net.cn

显式加密 (QE)

显式加密使用 MongoDB 驱动程序的加密库 (org.mongodb:mongodb-crypt)根据域模型内注释提供的元信息执行加密和解密任务。spring-doc.cadn.net.cn

官方不支持使用显式可查询加密。大胆的用户可以将@Encrypted@Queryable@ValueConverter(MongoEncryptionConverter.class)风险自负。spring-doc.cadn.net.cn

MongoEncryptionConverter 设置

转换器设置MongoEncryptionConverter需要几个步骤,因为涉及多个组件。 Bean 设置包括以下内容:spring-doc.cadn.net.cn

  1. ClientEncryption发动机spring-doc.cadn.net.cn

  2. 一个MongoEncryptionConverter实例配置为ClientEncryptionEncryptionKeyResolver.spring-doc.cadn.net.cn

  3. 一个PropertyValueConverterFactory使用 registeredMongoEncryptionConverter豆。spring-doc.cadn.net.cn

EncryptionKeyResolver使用EncryptionContext提供对属性的访问,允许动态 DEK 解析。spring-doc.cadn.net.cn

示例 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 设置一个Encryption引擎使用com.mongodb.client.vault.ClientEncryption. 该实例是有状态的,必须在使用后关闭。 Spring 会解决这个问题,因为ClientEncryptionCloseable.
2 设置基于注释的EncryptionKeyResolver以确定EncryptionKey来自注释。
3 创建MongoEncryptionConverter.
4 启用PropertyValueConverterBeanFactory.