Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
Javachevron-right

Java – Criptografia no nível do campo do lado do cliente

Maxime Beugnet14 min read • Published Feb 01, 2022 • Updated Mar 01, 2024
MongoDBSegurançaJava
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Início rápido
star-empty
star-empty
star-empty
star-empty
star-empty

Atualizações

O repositório de início rápido do MongoDB Java está disponível no GitHub.

28 de fevereiro de 2024

  • Atualizar para o Java 21
  • Atualize o driver Java para 5.0.0
  • Atualize logback-classic para 1.2.13

14 de novembro de 2023

  • Atualizar para o Java 17
  • Atualize o driver Java para 4.11.1
  • Atualize o mongodb-crypt para 1.8.0

25 de março de 2021

  • Atualize o driver Java para 4.2.2.
  • Exemplo de criptografia no nível do campo do lado do cliente adicionado.

21 de outubro de 2020

  • Atualize o driver Java para 4.1.1.
  • O registro do driver Java agora está ativado por meio da popular APISLF4J, então adicionei logback no pom.xml e um arquivo de configuração logback.xml.

O que é a criptografia no nível do campo do lado do cliente?

Emblema do Java
A criptografia no nível do campo do lado do cliente (CSFLE para abreviação) é um novo recurso adicionado no MongoDB 4.2 que permite criptografar alguns campos de seus documentos do MongoDB antes de transmiti-los pelo cabo para o cluster para armazenamento.
É a melhor peça de segurança contra qualquer tipo de intrusão ou bisbilhotar seu Cluster MongoDB. Somente o aplicativo com as chaves de criptografia corretas pode descriptografar e ler os dados protegidos.
Vamos conferir a API Java CSFLE com um exemplo simples.

Vídeo

Este conteúdo também está disponível em formato de vídeo.

Configuração

Usarei o mesmo repositório de sempre nesta série. Se você ainda não tiver uma cópia dele, poderá cloná-lo ou apenas atualizá-lo, caso já o tenha:
1git clone git@github.com:mongodb-developer/java-quick-start.git
Se você não configurou seu cluster gratuito no MongoDB Atlas, agora é um ótimo momento para fazê-lo. Você tem todas as instruções nesta publicação.
Para esta publicação de início rápido do CSFLE, usarei apenas a Community Edition do MongoDB. Na verdade, a única parte do CSFLE que é um recurso somente para empresas é a criptografia automática de campos, suportada pelo mongocryptd , ou pela Biblioteca Compartilhada de Criptografia Automática para Queryable Encryption.
Automatic Encryption Shared Library for Queryable Encryption substitui mongocryptd e deve ser a solução preferida. Eles são opcionais e fazem parte do MongoDB Enterprise.
Neste tutorial, usarei a criptografia explícita (ou manual) de campos que não requer mongocryptd ou Automatic Encryption Shared Library e a edição empresarial do MongoDB ou Atlas. Se você quiser explorar a versão empresarial do CSFLE com Java, poderá saber mais nesta documentação ou em minha publicação mais recente: Como implementar a criptografia no nível do campo do lado do cliente (CSFLE) em Java com o Spring Data MongoDB.
Não confunda mongocryptd ou o Automatic Encryption Shared Library com a bibliotecalibmongocrypt, que é a biblioteca C complementar usada pelos drivers para criptografar e descriptografar seus dados. Precisamos dessa biblioteca para executar o CSFLE. Eu adicionei no arquivopom.xmldeste projeto.
1<dependency>
2 <groupId>org.mongodb</groupId>
3 <artifactId>mongodb-crypt</artifactId>
4 <version>1.8.0</version>
5</dependency>
Para manter as amostras de código curtas e suaves nos exemplos abaixo, compartilharei apenas as partes mais relevantes. Se você quiser ver o código funcionando com todo o seu contexto, verifique o código fonte no repositório do github diretamente nopacote csfle.

Execute o código do Início rápido

Neste tutorial de início rápido, mostrarei a você a API CSFLE usando o Driver Java do MongoDB. Vou mostrar como:
  • crie e configure as conexões MongoDB que precisamos.
  • Criar uma chave mestra.
  • Crie chaves de criptografia de dados (DEK).
  • criar e ler documentos criptografados.
Para executar meu código do repositório acima, confira o README.
Mas, para resumir, o comando a seguir deve colocar você em funcionamento rapidamente:
1mvn compile exec:java -Dexec.mainClass="com.mongodb.quickstart.csfle.ClientSideFieldLevelEncryption" -Dmongodb.uri="mongodb+srv://USERNAME:PASSWORD@cluster0-abcde.mongodb.net/test?w=majority" -Dexec.cleanupDaemonThreads=false
Esta é a saída que você deve obter:
1**************
2* MASTER KEY *
3**************
4A new Master Key has been generated and saved to file "master_key.txt".
5Master Key: [100, 82, 127, -61, -92, -93, 0, -11, 41, -96, 89, -39, -26, -25, -33, 37, 85, -50, 64, 70, -91, 99, -44, -57, 18, 105, -101, -111, -67, -81, -19, 56, -112, 62, 11, 106, -6, 85, -125, 49, -7, -49, 38, 81, 24, -48, -6, -15, 21, -120, -37, -5, 65, 82, 74, -84, -74, -65, -43, -15, 40, 80, -23, -52, -114, -18, -78, -64, -37, -3, -23, -33, 102, -44, 32, 65, 70, -123, -97, -49, -13, 126, 33, -63, -75, -52, 78, -5, -107, 91, 126, 103, 118, 104, 86, -79]
6
7******************
8* INITIALIZATION *
9******************
10=> Creating local Key Management System using the master key.
11=> Creating encryption client.
12=> Creating MongoDB client with automatic decryption.
13=> Cleaning entire cluster.
14
15*************************************
16* CREATE KEY ALT NAMES UNIQUE INDEX *
17*************************************
18
19*******************************
20* CREATE DATA ENCRYPTION KEYS *
21*******************************
22Created Bobby's data key ID: 668a35af-df8f-4c41-9493-8d09d3d46d3b
23Created Alice's data key ID: 003024b3-a3b6-490a-9f31-7abb7bcc334d
24
25************************************************
26* INSERT ENCRYPTED DOCUMENTS FOR BOBBY & ALICE *
27************************************************
282 docs have been inserted.
29
30**********************************
31* FIND BOBBY'S DOCUMENT BY PHONE *
32**********************************
33Bobby document found by phone number:
34{
35 "_id": {
36 "$oid": "60551bc8dd8b737958e3733f"
37 },
38 "name": "Bobby",
39 "age": 33,
40 "phone": "01 23 45 67 89",
41 "blood_type": "A+",
42 "medical_record": [
43 {
44 "test": "heart",
45 "result": "bad"
46 }
47 ]
48}
49
50****************************
51* READING ALICE'S DOCUMENT *
52****************************
53Before we remove Alice's key, we can read her document.
54{
55 "_id": {
56 "$oid": "60551bc8dd8b737958e37340"
57 },
58 "name": "Alice",
59 "age": 28,
60 "phone": "09 87 65 43 21",
61 "blood_type": "O+"
62}
63
64***************************************************************
65* REMOVE ALICE's KEY + RESET THE CONNECTION (reset DEK cache) *
66***************************************************************
67Alice key is now removed: 1 key removed.
68=> Creating MongoDB client with automatic decryption.
69
70****************************************
71* TRY TO READ ALICE DOC AGAIN BUT FAIL *
72****************************************
73We get a MongoException because 'libmongocrypt' can't decrypt these fields anymore.
Vamos dar uma olhada em profundidade para entender o que está ocorrendo.

Como funciona

Diagrama CSFLE com chave mestra e cofre DEK
O CSFLE parece complicado, como qualquer recurso de segurança e criptografia, eu suponha. Vamos tentar simplificar em poucas palavras.
  1. Precisamos de uma chave mestra que desbloqueie todas as chaves de criptografia de dados (DEK, abreviadamente) que podemos usar para criptografar um ou mais campos em nossos documentos.
  2. Você pode usar uma DEK para todo o cluster ou uma DEK diferente para cada campo de cada documento no cluster. Depende de você.
  3. Os DEKs são armazenados em uma coleta em um cluster MongoDB que não precisa ser o mesmo que contém os dados criptografados. Os DEKs são armazenados criptografados. Eles são inúteis sem a chave mestre que precisa ser protegida.
  4. Você pode usar a criptografia manual (MongoDB Community Edition) ou automatizada (Enterprise Advanced ou Atlas) de campos.
  5. A descriptografia pode ser manual ou automatizada. Ambos fazem parte do MongoDB Community Edition. Nesta postagem, usarei criptografia manual e descriptografia automatizada para permanecer com o MongoDB Community Edition.

Conformidade com o GDPR

GDPR logo
As leis da Europa impõem proteção de dados e privacidade. Qualquer descuido pode resultar em multas massivas.
O CSFLE é uma ótima maneira de economizar milhões de dólares/euro.
Por exemplo, o CSFLE pode ser uma ótima maneira de impor a política de"direito ao fim" do GDPR. Se um usuário pedir para ser removido de seus sistemas, os dados deverão ser apagados do seu cluster de produção, é claro, mas também os registros, o ambiente de desenvolvimento e os backups... E convenhamos: dados dos backups. E se você restaurar ou usar esses backups, isso pode lhe custar milhões de dólares/euro.
Criptografe os dados de cada usuário com uma Chave de criptografia de dados (DEK) exclusiva e, para "esquecer" um usuário para sempre, tudo o que você precisa fazer é perder a chave. Portanto, salvar as DEKs em um cluster separado e aplicar uma política de baixa retenção nesse cluster garantirá que o usuário seja realmente esquecido para sempre quando a chave for excluída.
Kerneth White, Principal de Segurança do MongoDB que trabalhou no CSFLE, explica isso perfeitamente nesta resposta no Fórum da MongoDB Community.
Se a motivação principal for apenas garantir que os registros de usuário de texto simples excluídos permaneçam excluídos, não importa o que aconteça, isso se tornará uma estratégia simples de sincronização e separação de preocupações, e a solução mais direta é mover a coleção de keyvault para um banco de dados ou cluster completamente diferente, configurado com uma retenção de backup muito mais curta; o FLE não pressupõe que a coleção de keyvault criptografada seja co-residente com o cluster ativo ou tenha os mesmos controles de acesso e histórico de backup, apenas que o cliente possa, quando necessário, fazer uma conexão autenticada com esse banco de dados de keyvault. No entanto, é importante observar que, com um ciclo de backup mais curto, no caso de alguma corrupção catastrófica de dados (maliciosa, intencional ou acidental), todas as chaves desse banco de dados (e, portanto, todos os dados criptografados) são tão recuperáveis no momento quanto o backup mais curto do keyvault restauraria.
É mais trivial, mas, no caso de uma invasão, todos os dados roubados serão completamente inúteis sem a chave mestra e não resultarão em uma multa ruinosa.

A Chave Mestra

A chave mestra é uma matriz de 96 bytes. Ele pode ser armazenado em um Serviço de Gerenciamento de Chaves em um provedor de nuvem ou pode ser gerenciado localmente (documentação). De uma forma ou de outra, você deve protegê-lo de qualquer ameaça.
É tão simples quanto gerar um novo:
1final byte[] masterKey = new byte[96];
2new SecureRandom().nextBytes(masterKey);
Mas provavelmente você só quer fazer isso uma vez e depois reutilizar o mesmo sempre que reiniciar o aplicativo.
Aqui está minha implementação para armazená-lo em um arquivo local pela primeira vez e depois reutilizá-lo a cada reinicialização.
1import java.io.FileInputStream;
2import java.io.FileOutputStream;
3import java.io.IOException;
4import java.security.SecureRandom;
5import java.util.Arrays;
6
7public class MasterKey {
8
9 private static final int SIZE_MASTER_KEY = 96;
10 private static final String MASTER_KEY_FILENAME = "master_key.txt";
11
12 public static void main(String[] args) {
13 new MasterKey().tutorial();
14 }
15
16 private void tutorial() {
17 final byte[] masterKey = generateNewOrRetrieveMasterKeyFromFile(MASTER_KEY_FILENAME);
18 System.out.println("Master Key: " + Arrays.toString(masterKey));
19 }
20
21 private byte[] generateNewOrRetrieveMasterKeyFromFile(String filename) {
22 byte[] masterKey = new byte[SIZE_MASTER_KEY];
23 try {
24 retrieveMasterKeyFromFile(filename, masterKey);
25 System.out.println("An existing Master Key was found in file \"" + filename + "\".");
26 } catch (IOException e) {
27 masterKey = generateMasterKey();
28 saveMasterKeyToFile(filename, masterKey);
29 System.out.println("A new Master Key has been generated and saved to file \"" + filename + "\".");
30 }
31 return masterKey;
32 }
33
34 private void retrieveMasterKeyFromFile(String filename, byte[] masterKey) throws IOException {
35 try (FileInputStream fis = new FileInputStream(filename)) {
36 fis.read(masterKey, 0, SIZE_MASTER_KEY);
37 }
38 }
39
40 private byte[] generateMasterKey() {
41 byte[] masterKey = new byte[SIZE_MASTER_KEY];
42 new SecureRandom().nextBytes(masterKey);
43 return masterKey;
44 }
45
46 private void saveMasterKeyToFile(String filename, byte[] masterKey) {
47 try (FileOutputStream fos = new FileOutputStream(filename)) {
48 fos.write(masterKey);
49 } catch (IOException e) {
50 e.printStackTrace();
51 }
52 }
53}
Isso não é nem de longe seguro para um ambiente de produção, pois deixar o master_key.txt diretamente na pasta do aplicativo em seu servidor de produção é como deixar a combinação do cofre em uma nota. Proteja esse arquivo ou considere usar um KMS em produção.
Neste início rápido simples, usarei apenas uma única chave mestre, mas é totalmente possível usar várias chaves mestres.

Provedor do Serviço de Gerenciamento de Chaves (KMS)

Qualquer que seja a solução escolhida para a chave mestra, você precisará de um provedor de KMS para configurar o ClientEncryptionSettings e o AutoEncryptionSettings.
Esta é a configuração de um KMS local:
1Map<String, Map<String, Object>> kmsProviders = new HashMap<String, Map<String, Object>>() {{
2 put("local", new HashMap<String, Object>() {{
3 put("key", localMasterKey);
4 }});
5}};

Os clientes

Precisamos configurar dois clientes diferentes:
  • O primeiro ─ ClientEncryption ─ será usado para criar nossas Chaves de Criptografia de Dados (DEK) e criptografar nossos campos manualmente.
  • A segunda ─ MongoClient ─ será a conexão MongoDB mais convencional que usaremos para ler e gravar nossos documentos, com a diferença de que ela será configurada para descriptografar automaticamente os campos criptografados.

ClientEncryption

1ConnectionString connection_string = new ConnectionString("mongodb://localhost");
2MongoClientSettings kvmcs = MongoClientSettings.builder().applyConnectionString(connection_string).build();
3
4ClientEncryptionSettings ces = ClientEncryptionSettings.builder()
5 .keyVaultMongoClientSettings(kvmcs)
6 .keyVaultNamespace("csfle.vault")
7 .kmsProviders(kmsProviders)
8 .build();
9
10ClientEncryption encryption = ClientEncryptions.create(ces);

Cliente Mongo

1AutoEncryptionSettings aes = AutoEncryptionSettings.builder()
2 .keyVaultNamespace("csfle.vault")
3 .kmsProviders(kmsProviders)
4 .bypassAutoEncryption(true)
5 .build();
6
7MongoClientSettings mcs = MongoClientSettings.builder()
8 .applyConnectionString(connection_string)
9 .autoEncryptionSettings(aes)
10 .build();
11
12MongoClient client = MongoClients.create(mcs);
bypassAutoEncryption(true) é o ticket da Community Edition. Sem ele, mongocryptd ou Automatic Encryption Shared Library dependeria do JSON schema que você teria que fornecer para criptografar automaticamente os documentos. Veja este exemplo na documentação.
Você não precisa reutilizar a mesma connection string para ambas as conexões. Na verdade, seria muito mais "compatível com o GDPR" usar clusters separados, para que você possa impor uma política de baixa retenção nas Chaves de criptografia de dados.

Índice exclusivo em nomes alternativos de chaves

A primeira coisa que você deve fazer antes de criar sua primeira chave de criptografia de dados é criar um índice exclusivo nos nomes alternativos da chave para garantir que você não possa reutilizar o mesmo nome alternativo em duas DEKs diferentes.
Esses nomes o ajudarão a "etiquetar" suas chaves para saber para que cada uma delas é usada ─ o que ainda depende totalmente de você.
1MongoCollection<Document> vaultColl = client.getDatabase("csfle").getCollection("vault");
2vaultColl.createIndex(ascending("keyAltNames"),
3 new IndexOptions().unique(true).partialFilterExpression(exists("keyAltNames")));
No meu exemplo, opto por usar uma DEK por usuário. Criptografarei todos os campos que deseja proteger em cada documento de usuário com a mesma chave. Se eu quiser "esquecer" um usuário, só preciso soltar essa chave. No meu exemplo, os nomes são exclusivos, então estou usando isso para o meu keyAltNames. É uma ótima maneira de impor a conformidade com o GDPR.

Criar chaves de criptografia de dados

Vamos criar duas chaves de criptografia de dados: uma para Bobby e outra para Alice. Cada um será usado para criptografar todos os campos que desejo manter seguros em meus respectivos documentos de usuário.
1BsonBinary bobbyKeyId = encryption.createDataKey("local", keyAltName("Bobby"));
2BsonBinary aliceKeyId = encryption.createDataKey("local", keyAltName("Alice"));
Recebemos uma pequena ajuda desse método privado para facilitar a leitura do meu código:
1private DataKeyOptions keyAltName(String altName) {
2 return new DataKeyOptions().keyAltNames(List.of(altName));
3}
Esta é a aparência do DEK do Bobby em minha csfle.vault collection:
1{
2 "_id" : UUID("aaa2e53d-875e-49d8-9ce0-dec9a9658571"),
3 "keyAltNames" : [ "Bobby" ],
4 "keyMaterial" : BinData(0,"/ozPZBMNUJU9udZyTYe1hX/KHqJJPrjdPads8UNjHX+cZVkIXnweZe5pGPpzcVcGmYctTAdxB3b+lmY5ONTzEZkqMg8JIWenIWQVY5fogIpfHDJQylQoEjXV3+e3ZY1WmWJR8mOp7pMoTyoGlZU2TwyqT9fcN7E5pNRh0uL3kCPk0sOOxLT/ejQISoY/wxq2uvyIK/C6/LrD1ymIC9w6YA=="),
5 "creationDate" : ISODate("2021-03-19T16:16:09.800Z"),
6 "updateDate" : ISODate("2021-03-19T16:16:09.800Z"),
7 "status" : 0,
8 "masterKey" : {
9 "provider" : "local"
10 }
11}
Como você pode ver acima, o keyMaterial (o próprio DEK) é criptografado pela chave mestre. Sem a chave mestre para descriptografá-lo, é inútil. Além disso, você pode identificar que é a chave de Device no campo keyAltNames.

Criar documentos criptografados

Agora que temos uma chave de criptografia para Bobby e Alice, posso criar seus respectivos documentos e inseri-los no MongoDB da seguinte forma:
1private static final String DETERMINISTIC = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic";
2private static final String RANDOM = "AEAD_AES_256_CBC_HMAC_SHA_512-Random";
3
4private Document createBobbyDoc(ClientEncryption encryption) {
5 BsonBinary phone = encryption.encrypt(new BsonString("01 23 45 67 89"), deterministic(BOBBY));
6 BsonBinary bloodType = encryption.encrypt(new BsonString("A+"), random(BOBBY));
7 BsonDocument medicalEntry = new BsonDocument("test", new BsonString("heart")).append("result", new BsonString("bad"));
8 BsonBinary medicalRecord = encryption.encrypt(new BsonArray(List.of(medicalEntry)), random(BOBBY));
9 return new Document("name", BOBBY).append("age", 33)
10 .append("phone", phone)
11 .append("blood_type", bloodType)
12 .append("medical_record", medicalRecord);
13}
14
15private Document createAliceDoc(ClientEncryption encryption) {
16 BsonBinary phone = encryption.encrypt(new BsonString("09 87 65 43 21"), deterministic(ALICE));
17 BsonBinary bloodType = encryption.encrypt(new BsonString("O+"), random(ALICE));
18 return new Document("name", ALICE).append("age", 28).append("phone", phone).append("blood_type", bloodType);
19}
20
21private EncryptOptions deterministic(String keyAltName) {
22 return new EncryptOptions(DETERMINISTIC).keyAltName(keyAltName);
23}
24
25private EncryptOptions random(String keyAltName) {
26 return new EncryptOptions(RANDOM).keyAltName(keyAltName);
27}
28
29private void createAndInsertBobbyAndAlice(ClientEncryption encryption, MongoCollection<Document> usersColl) {
30 Document bobby = createBobbyDoc(encryption);
31 Document alice = createAliceDoc(encryption);
32 int nbInsertedDocs = usersColl.insertMany(List.of(bobby, alice)).getInsertedIds().size();
33 System.out.println(nbInsertedDocs + " docs have been inserted.");
34}
Veja como são os documentos do Bobby e da Alice em minha coleçãoencrypted.users:
Bobby
1{
2 "_id" : ObjectId("6054d91c26a275034fe53300"),
3 "name" : "Bobby",
4 "age" : 33,
5 "phone" : BinData(6,"ATKkRdZWR0+HpqNyYA7zgIUCgeBE4SvLRwaXz/rFl8NPZsirWdHRE51pPa/2W9xgZ13lnHd56J1PLu9uv/hSkBgajE+MJLwQvJUkXatOJGbZd56BizxyKKTH+iy+8vV7CmY="),
6 "blood_type" : BinData(6,"AjKkRdZWR0+HpqNyYA7zgIUCUdc30A8lTi2i1pWn7CRpz60yrDps7A8gUJhJdj+BEqIIx9xSUQ7xpnc/6ri2/+ostFtxIq/b6IQArGi+8ZBISw=="),
7 "medical_record" : BinData(6,"AjKkRdZWR0+HpqNyYA7zgIUESl5s4tPPvzqwe788XF8o91+JNqOUgo5kiZDKZ8qudloPutr6S5cE8iHAJ0AsbZDYq7XCqbqiXvjQobObvslR90xJvVMQidHzWtqWMlzig6ejdZQswz2/WT78RrON8awO")
8}
Alice
1{
2 "_id" : ObjectId("6054d91c26a275034fe53301"),
3 "name" : "Alice",
4 "age" : 28,
5 "phone" : BinData(6,"AX7Xd65LHUcWgYj+KbUT++sCC6xaCZ1zaMtzabawAgB79quwKvld8fpA+0m+CtGevGyIgVRjtj2jAHAOvREsoy3oq9p5mbJvnBqi8NttHUJpqooUn22Wx7o+nlo633QO8+c="),
6 "blood_type" : BinData(6,"An7Xd65LHUcWgYj+KbUT++sCTyp+PJXudAKM5HcdX21vB0VBHqEXYSplHdZR0sCOxzBMPanVsTRrOSdAK5yHThP3Vitsu9jlbNo+lz5f3L7KYQ==")
7}
O Client Code Level Field Level Encryption fornece atualmente dois algoritmos diferentes para criptografar os dados que você deseja proteger.

AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic

Com esse algoritmo, o resultado da criptografia ─ dadas as mesmas entradas (valor e DEK) ─ é determinístico. Isso significa que temos um suporte maior para operações de leitura, mas dados criptografados com baixa cardinalidade são suscetíveis a ataques de análise de frequência.
No meu exemplo, se quiser recuperar usuários por números de telefone, devo usar o algoritmo determinístico. Como um número de telefone provavelmente será exclusivo em minha collection de usuários, é seguro usar este algoritmo aqui.

AEAD_AES_256_CBC_HMAC_SHA_512-Random

Com esse algoritmo, o resultado da criptografia é sempre diferente. Isso significa que ele fornece as mais fortes garantias de confidencialidade de dados, mesmo quando a cardinalidade é baixa, mas impede operações de leitura baseadas nesses campos.
No meu exemplo, o tipo de corpo tem uma baixa cardinalidade e não faz sentido para o Atlas Search na minha coleção de usuário por tipo de corpo de qualquer maneira, então é seguro usar este algoritmo para este campo.
Além disso, o prontuário médico de Bobby deve ser muito seguro. Portanto, todo o subdocumento que contém todos os registros médicos dele também está criptografado com o algoritmo aleatório e não será usado para pesquisar o Bobby na minha coleção.

Leia o documento do Bobby

Conforme mencionado na seção anterior, é possível pesquisar documentos por campos criptografados com o algoritmo determinístico.
Veja como:
1BsonBinary phone = encryption.encrypt(new BsonString("01 23 45 67 89"), deterministic(BOBBY));
2String doc = usersColl.find(eq("phone", phone)).first().toJson();
Simplesmente criptografo novamente, com a mesma chave, o número de telefone que estou procurando, e posso usar esse BsonBinary na minha consulta para encontrar Bobby.
Se eu produzir a stringdoc , obterei:
1{
2 "_id": {
3 "$oid": "6054d91c26a275034fe53300"
4 },
5 "name": "Bobby",
6 "age": 33,
7 "phone": "01 23 45 67 89",
8 "blood_type": "A+",
9 "medical_record": [
10 {
11 "test": "heart",
12 "result": "bad"
13 }
14 ]
15}
Como você pode ver, a descriptografia automática funcionou conforme o esperado, posso ver meu documento em texto não criptografado. Para encontrar este documento, eu poderia usar o _id, o name, o ageou o número de telefone, mas não o blood_type ou o medical_record.

Leia o documento da Alice

Agora vamos testar o CSFLE. Quero ter certeza de que, se a DEK de Alice for destruída, o documento de Alice estará perdido para sempre e nunca poderá ser restaurado, mesmo a partir de um backup que possa ser restaurado. É por isso que é importante manter os DEKs e os documentos criptografados em dois clusters diferentes que não tenham a mesma política de retenção de backup.
Vamos recuperar o documento de Alice por nome, mas vamos proteger meu código caso algo "ruim" tenha acontecido com a chave dela...
1private void readAliceIfPossible(MongoCollection<Document> usersColl) {
2 try {
3 String aliceDoc = usersColl.find(eq("name", ALICE)).first().toJson();
4 System.out.println("Before we remove Alice's key, we can read her document.");
5 System.out.println(aliceDoc);
6 } catch (MongoException e) {
7 System.err.println("We get a MongoException because 'libmongocrypt' can't decrypt these fields anymore.");
8 }
9}
Se a chave dela ainda existir no banco de dados, posso descriptografar o documento:
1{
2 "_id": {
3 "$oid": "6054d91c26a275034fe53301"
4 },
5 "name": "Alice",
6 "age": 28,
7 "phone": "09 87 65 43 21",
8 "blood_type": "O+"
9}
Agora, vamos remover sua chave do banco de dados:
1vaultColl.deleteOne(eq("keyAltNames", ALICE));
Em um ambiente de produção da vida real, não faria sentido ler seu documento novamente; e como todos nós somos desenvolvedores profissionais e organizados que queremos manter as coisas organizadas, também excluiremos o documento de Alice junto com sua DEK, já que esse documento agora é completamente inútil para nós.
No meu exemplo, quero tentar ler este documento de qualquer maneira. Mas se eu tentar lê-lo imediatamente após excluir o documento dela, há uma grande chance de que eu ainda consiga fazê-lo por causa do cache de chave de criptografia de dados de60 segundos que é gerenciado pelo libmongocrypt.
Esse cache é muito importante porque, sem ele, várias idas e voltas seriam necessárias para descriptografar meu documento. É fundamental evitar que o CSFLE acabe com o desempenho do seu cluster MongoDB.
Então, para ter certeza de que não estou mais usando esse cache, estou criando um novo MongoClient (continuando com as configurações de descriptografia automática) para este exemplo. Mas é claro que, na produção, não faria sentido fazer isso.
Agora, se eu tentar acessar o documento da Alice novamente, obtenho o seguinte MongoException, como esperado:
1com.mongodb.MongoException: not all keys requested were satisfied
2 at com.mongodb.MongoException.fromThrowableNonNull(MongoException.java:83)
3 at com.mongodb.client.internal.Crypt.fetchKeys(Crypt.java:286)
4 at com.mongodb.client.internal.Crypt.executeStateMachine(Crypt.java:244)
5 at com.mongodb.client.internal.Crypt.decrypt(Crypt.java:128)
6 at com.mongodb.client.internal.CryptConnection.command(CryptConnection.java:121)
7 at com.mongodb.client.internal.CryptConnection.command(CryptConnection.java:131)
8 at com.mongodb.internal.operation.CommandOperationHelper.executeCommand(CommandOperationHelper.java:345)
9 at com.mongodb.internal.operation.CommandOperationHelper.executeCommand(CommandOperationHelper.java:336)
10 at com.mongodb.internal.operation.CommandOperationHelper.executeCommandWithConnection(CommandOperationHelper.java:222)
11 at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:658)
12 at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:652)
13 at com.mongodb.internal.operation.OperationHelper.withReadConnectionSource(OperationHelper.java:583)
14 at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:652)
15 at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:80)
16 at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:170)
17 at com.mongodb.client.internal.FindIterableImpl.first(FindIterableImpl.java:200)
18 at com.mongodb.quickstart.csfle.ClientSideFieldLevelEncryption.readAliceIfPossible(ClientSideFieldLevelEncryption.java:91)
19 at com.mongodb.quickstart.csfle.ClientSideFieldLevelEncryption.demo(ClientSideFieldLevelEncryption.java:79)
20 at com.mongodb.quickstart.csfle.ClientSideFieldLevelEncryption.main(ClientSideFieldLevelEncryption.java:41)
21Caused by: com.mongodb.crypt.capi.MongoCryptException: not all keys requested were satisfied
22 at com.mongodb.crypt.capi.MongoCryptContextImpl.throwExceptionFromStatus(MongoCryptContextImpl.java:145)
23 at com.mongodb.crypt.capi.MongoCryptContextImpl.throwExceptionFromStatus(MongoCryptContextImpl.java:151)
24 at com.mongodb.crypt.capi.MongoCryptContextImpl.completeMongoOperation(MongoCryptContextImpl.java:93)
25 at com.mongodb.client.internal.Crypt.fetchKeys(Crypt.java:284)
26 ... 17 more

Encerrando

Neste tutorial de início rápido, descobre-se como usar a criptografia em nível de campo do lado do cliente com o driver Java do MongoDB, usando apenas a MongoDB Community Edition. Você pode saber mais sobre a criptografia automatizada em nossa documentação.
O CSFLE é o recurso de segurança mais recente para garantir o nível máximo de segurança para o seu cluster. Nem mesmo seus administradores poderão acessar os dados em produção se não tiverem acesso às chaves mestras.
Mas não é a única medida de segurança que você deve usar para proteger seu cluster. Impedir o acesso ao seu cluster é, obviamente, a primeira medida de segurança que você deve impor,habilitando a autenticação e limitando a exposição da rede.
Em caso de dúvidas, confira a checklist de segurança antes de iniciar um cluster em produção para ter certeza de que não ignorou nenhuma das opções de segurança que o MongoDB tem a oferecer para proteger seus dados.
Há muita flexibilidade na implementação do CSFLE: você pode optar por usar uma ou várias chaves mestras, o mesmo para as chaves de criptografia de dados. Você também pode optar por criptografar todos os seus números de telefone em sua collection com o mesmo DEK ou usar um diferente para cada usuário. Depende de você como organizará sua estratégia de criptografia, mas, é claro, certifique-se de que ela cumpra todas as suas obrigações legais. Existem várias maneiras certas de implementar o CSFLE, portanto, certifique-se de encontrar a mais adequada para o seu caso de uso.
Se tiver dúvidas, acesse o site da nossa comunidade de desenvolvedores, no qual os engenheiros e a comunidade do MongoDB ajudarão você a desenvolver sua próxima grande ideia com o MongoDB.

Documentação


Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Início rápido
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Exemplo de código

Crie um rastreador de livros Java do MongoDB Spring Boot para iniciantes


Mar 22, 2023 | 0 min read
Início rápido

Transações ACID multidocumento Java - MongoDB


Mar 01, 2024 | 10 min read
Início rápido

Pipeline de agregação Java


Oct 01, 2024 | 8 min read
Tutorial

Spring Data Unlocked: Começando com Java e MongoDB


Nov 11, 2024 | 5 min read
Sumário