Neste guia, você pode aprender a usar o provedor EF Core para criptografar campos de documentos específicos usando Queryable Encryption (QE).
Visão geral
O Queryable Encryption criptografa campos de documento confidenciais na camada de aplicativo antes de gravar dados no MongoDB, permitindo que seu aplicativo ainda realize query nesses campos. Somente aplicativos que têm acesso às suas chaves de criptografia podem ler os dados em texto simples. Se um invasor obtiver acesso ao banco de dados, ele só poderá ver o texto cifrado porque não tem acesso às chaves de criptografia.
Por exemplo, você pode usar Queryable Encryption para criptografar campos que contêm:
Números de Segurança Social
Números de cartão de crédito
Informações de saúde ou médicas
Informações financeiras
Qualquer outra informação sensível ou pessoalmente identificável
O provedor EF Core oferece suporte à Queryable Encryption por meio de uma API de modelo fluente. Você configura quais propriedades da entidade devem ser criptografadas usando o método OnModelCreating(), e o provedor lida com a criptografia automaticamente ao ler e gravar dados.
Pré-requisitos
Antes de configurar o Queryable Encryption com o provedor EF Core, certifique-se de ter o seguinte:
Um cluster MongoDB Enterprise ou MongoDB Atlas executando o MongoDB 7.0 ou posterior.
Acesso a um Key Management Service (KMS). Os provedores de KMS compatíveis incluem Amazon Web Services, Azure, Google Cloud Platform, o KMIP (Key Management Interoperability Protocol) e provedores de chaves locais.
A biblioteca de criptografia automática (
CRYPT_SHARED) oumongocryptdinstalada em seu ambiente. Para aprender como instalar a biblioteca compartilhada, consulte Instalar um componente de análise de query na documentação do MongoDB Server.
Habilitar queryable encryption
As seções a seguir descrevem como configurar opções de criptografia em seu contexto e marcar propriedades de entidade para criptografia em seu modelo:
Configurar opções de criptografia
Antes de configurar qualquer contexto que use Queryable Encryption, você deve registrar o provedor de criptografia automática uma vez para seu aplicativo executando o seguinte código:
MongoClientSettings.Extensions.AddAutoEncryption();
Em seguida, crie uma instância MongoOptionsExtension e encadeie os seguintes métodos antes de passar a instância para o método UseMongoDB():
WithKmsProviders()— especifica seu provedor de KMS e credenciais.WithKeyVaultNamespace()— especifica a coleção usada para armazenar chaves de criptografia de dados.WithCryptProvider()— especifica a biblioteca de criptografia a ser utilizada e seu caminho.
O exemplo a seguir configura um provedor KMS local para uso em desenvolvimento:
var kmsProviders = new Dictionary< string, IReadOnlyDictionary<string, object>> { { "local", new Dictionary<string, object> { { "key", localMasterKey } } } }; var keyVaultNamespace = CollectionNamespace.FromFullName( "encryption.__keyVault"); var mongoOptions = new MongoOptionsExtension() .WithConnectionString(connectionString) .WithDatabaseName("myDatabase") .WithKmsProviders(kmsProviders) .WithKeyVaultNamespace(keyVaultNamespace) .WithCryptProvider( CryptProvider.AutoEncryptSharedLibrary, Environment.GetEnvironmentVariable("CRYPT_SHARED_LIB_PATH")); var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>() .UseMongoDB(mongoOptions);
Para usar mongocryptd em vez da biblioteca compartilhada, passe CryptProvider.Mongocryptd e o caminho para o binário mongocryptd para o método WithCryptProvider().
Aviso
Não use um provedor KMS local na produção. Sem um KMS remoto, você corre o risco de acesso não autorizado à chave mestre ou perda permanente da chave necessária para descriptografar seus dados.
Marcar campos para criptografia
No método OnModelCreating(), chame um método de criptografia em cada propriedade que você deseja criptografar. O método que você escolher controla quais tipos de query estão disponíveis nesse campo:
Método | Suporte a consultas | Notas |
|---|---|---|
| none | Criptografa o campo sem suporte a query. Use para campos que você armazena, mas nunca filtra diretamente. |
| Igualdade ( | Não disponível para os tipos de armazenamento BSON |
| Faixa ( | Suportado apenas para os tipos de armazenamento BSON |
Para criptografar uma entidade de propriedade em vez de uma propriedade escalar, chame IsEncrypted(dataKeyId) no OwnedNavigationBuilder ou OwnershipBuilder retornado de OwnsOne() ou OwnsMany().
Para obter um exemplo completo que usa os métodos anteriores, consulte a seção Exemplo: criptografar dados do paciente.
Exemplo: Criptografar dados do paciente
A seguinte entidade Patient define o document model, com os campos SSN e DateOfBirth para criptografar:
public class Patient { public ObjectId Id { get; set; } public string Name { get; set; } = null!; public string SSN { get; set; } = null!; public DateTime DateOfBirth { get; set; } }
Os HospitalContext a seguir marcam esses campos para criptografia no método OnModelCreating(). SSN é criptografado sem suporte a query, e DateOfBirth é criptografado com suporte a query de faixa. O construtor aceita os IDs de duas chaves de criptografia de dados, que você cria em seu cofre de chaves antes de inicializar o contexto:
public class HospitalContext : DbContext { public DbSet<Patient> Patients { get; set; } = null!; private readonly Guid _ssnDataKeyId; private readonly Guid _dobDataKeyId; public HospitalContext( DbContextOptions options, Guid ssnDataKeyId, Guid dobDataKeyId) : base(options) { _ssnDataKeyId = ssnDataKeyId; _dobDataKeyId = dobDataKeyId; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Entity<Patient>(entity => { entity.ToCollection("patients"); entity.Property(p => p.SSN) .IsEncrypted(_ssnDataKeyId); entity.Property(p => p.DateOfBirth) .IsEncryptedForRange( new DateTime(1900, 1, 1), new DateTime(2100, 12, 31), _dobDataKeyId); }); } }
O código a seguir configura as opções de criptografia, instancia o HospitalContext com os IDs da chave de dados e insere e consulta um documento Patient:
var mongoOptions = new MongoOptionsExtension() .WithConnectionString("<connection string URI>") .WithDatabaseName("hospitalDb") .WithKmsProviders(kmsProviders) .WithKeyVaultNamespace(keyVaultNamespace) .WithCryptProvider( CryptProvider.AutoEncryptSharedLibrary, Environment.GetEnvironmentVariable("CRYPT_SHARED_LIB_PATH")); using var context = new HospitalContext( new DbContextOptionsBuilder<HospitalContext>() .UseMongoDB(mongoOptions) .Options, ssnDataKeyId, dobDataKeyId); context.Database.EnsureCreated(); context.Patients.Add(new Patient { Name = "John Doe", SSN = "123-45-6789", DateOfBirth = new DateTime(1985, 6, 15) }); context.SaveChanges(); var results = context.Patients .Where(p => p.DateOfBirth > new DateTime(1980, 1, 1)) .ToList();
Suporte a esquemas do lado do servidor
Por padrão, o provedor EF Core aplica sua configuração de criptografia de campo apenas ao cliente. A criptografia somente do cliente é apropriada durante o desenvolvimento, quando seu esquema de criptografia ainda pode estar evoluindo.
Para implantações de produção, registre o esquema de criptografia no servidor ao criar a coleção. Depois que o servidor mantiver o esquema, ele forçará a criptografia independentemente da configuração do cliente, protegendo contra gravações acidentais de texto simples de clientes mal configurados. Depois de registrar o esquema no servidor, você não poderá alterar quais campos são criptografados sem recriar a coleção.
Para criar uma coleção com um esquema do lado do servidor, passe o Model do seu contexto para QueryableEncryptionSchemaGenerator.GenerateSchemas(). Em seguida, passe o resultado para o método CreateCollection(), como mostrado no exemplo a seguir:
var encryptedSchemas = QueryableEncryptionSchemaGenerator.GenerateSchemas( context.Model); using var client = new MongoClient( "<connection string URI>"); var database = client.GetDatabase("hospitalDb"); foreach (var entityType in context.Model .GetEntityTypes() .Where(e => e.IsDocumentRoot())) { var collectionName = entityType.GetCollectionName(); if (encryptedSchemas.TryGetValue( collectionName, out var schema)) { database.CreateCollection( collectionName, new CreateCollectionOptions { EncryptedFields = schema }); } } context.Database.EnsureCreated();
Depois que a coleção criptografada existir no servidor, você poderá configurar novas instâncias de contexto para usar apenas o esquema do servidor. Defina QueryableEncryptionSchemaMode.Ignore no MongoOptionsExtension, como mostrado no exemplo a seguir:
var mongoOptions = new MongoOptionsExtension() .WithConnectionString("<connection string URI>") .WithDatabaseName("hospitalDb") .WithKmsProviders(kmsProviders) .WithKeyVaultNamespace(keyVaultNamespace) .WithCryptProvider( CryptProvider.AutoEncryptSharedLibrary, Environment.GetEnvironmentVariable("CRYPT_SHARED_LIB_PATH")) .WithQueryableEncryptionSchemaMode( QueryableEncryptionSchemaMode.Ignore);
No modo Ignore, qualquer configuração IsEncrypted no método OnModelCreating() não tem efeito na criptografia. O esquema do servidor controla quais campos são criptografados.
Informações adicionais
Para saber mais sobre Queryable Encryption, consulte as seções Queryable Encryption e Casos de Uso de Queryable Encryption no manual do MongoDB Server.
Para obter detalhes completos da implementação, consulte a documentação da API do provedor EF Core.