Usando a criptografia de campo no MongoDB

Originally written for Percona Blog in June, 2021 –  https://www.percona.com/blog/using-the-mongodb-field-encryption-feature
Um dos principais tópicos atualmente é, sem dúvida, a segurança. Na rotina, isso pode passar despercebido, mas, cedo ou mais tarde, precisamos implementar ou seguir algumas diretrizes de segurança. Hoje, vamos discutir uma delas: a Criptografia de Campo.

Introdução.

Falando especificamente sobre o recurso, ele está disponível apenas a partir das versões 4.2+ do MongoDB. O MongoDB oferece dois métodos de Criptografia de Campos:
  1. Criptografia automática no nível do campo do lado do cliente
  2. Criptografia explícita (manual) no nível do campo do lado do cliente
O modo automático está disponível apenas na Enterprise Edition e no Atlas, enquanto o método manual é suportado na Community Edition pelos drivers do MongoDB e também pelo mongo shell. Este artigo utilizará o Percona Server for MongoDB (PSMDB) na versão 4.4, com autenticação habilitada, e aplicará o método manual. Como o objetivo aqui é demonstrar a funcionalidade, usaremos o mongo shell para realizar todas as operações. No entanto, para aplicações, a abordagem mais recomendada é implementar a criptografia via driver. A documentação oficial lista detalhadamente os drivers suportados para criptografia no nível de campo: https://www.mongodb.com/pt-br/docs/v5.0/core/security-client-side-encryption/#std-label-field-level-encryption-drivers  

How to:

  • 1. Para começar a usar o recurso e para fins ilustrativos, utilizaremos um Keyfile gerenciado localmente como nosso Serviço de Gerenciamento de Chaves(Key Management Service – KMS).
É importante mencionar que um keyfile local é rápido de configurar, mas oferece menor segurança. Por isso, não é recomendado em ambientes de produção, pois a chave é armazenada junto com o banco de dados. Em ambientes de produção, considere utilizar um dos seguintes serviços como Serviço de Gerenciamento de Chaves (KMS):
  • Amazon Web Services KMS
  • Azure Key Vault
  • Google Cloud Platform KMS
Ao utilizar um Keyfile gerenciado localmente, o MongoDB exige que o arquivo contenha uma string codificada em base64 de 96 bytes, sem quebras de linha. Essa chave pode ser criada utilizando o exemplo abaixo: ⚠️ – Certifique-se de salvar o keyfile em um local seguro para evitar perdê-lo. Caso contrário, não será mais possível descriptografar, portanto não ler os dados posteriormente.
  • 2. Após criar o keyfile, vamos abrir uma sessão do mongo shell com o banco de dados, mas sem nos conectar ainda.
Utilizaremos a opção --nodb para iniciar o shell sem conexão imediata ao banco de dados. Também utilizaremos --shell para executar o código fornecido (neste caso, o valor da string fornecida ao --eval) sem que a sessão seja encerrada automaticamente no final. Esse passo é necessário porque precisamos carregar o keyfile em um objeto que posteriormente se tornará uma propriedade da conexão com o banco de dados. No exemplo a seguir, estamos carregando o keyfile na variável de banco de dados LOCAL_KEY:
  • 4. Após definir a variável, podemos estabelecer uma conexão habilitada para FLE (Field Level Encryption) utilizando as variáveis configuradas acima no construtor Mongo().
Essa conexão também utiliza autenticação padrão com nome de usuário e senha, como pode ser observado na string URI mongodb://.../.
  • 5. O próximo passo será criar o objeto interno do key vault em si. Até o momento, estávamos definindo variáveis e ajustando as conexões do cliente para prosseguir. Isso pode ser feito da seguinte maneira para o key vault:
  • 5.1. Para fins de ilustração, como o comando acima não gera saída visível, podemos verificar a estrutura recém-criada do key vault em uma sessão diferente:
  • 6. Com tudo configurado e as estruturas do key vault implementadas, o próximo passo é adicionar uma chave de criptografia de dados ao key vault da conexão do banco de dados. Se bem-sucedido, o comando createKey() retorna o UUID da nova chave de criptografia de dados. Este UUID, que é um BSON Binary, será usado para criptografar os campos manualmente:
  • 7. Agora, vamos inserir um documento utilizando a chave criada acima para criptografar. Note que todas as operações anteriores foram feitas na mesma sessão do mongo-shell, e para criptografar, usaremos o método encrypt() junto com os parâmetros necessários para ocultar o SSN: “123-45-6789”.
  • 7.1. A função encrypt()  requer os seguintes 3 argumentos para criptografar um campo:
    • encryptionKeyId – Este é o UUID da chave gerada.
    • Value – Neste exemplo, ocultaremos o valor “123-45-6789” do campo SSN.
    • encryptionAlgorithm – O algoritmo de criptografia a ser usado. Podemos escolher entre:
      • Deterministic Encryption
      • Randomized Encryption
  • 7.2. Com tudo configurado, podemos inserir o documento criptografando o campo da seguinte maneira:
Perfeito! Conseguimos criptografar manualmente o campo. 🎉   Agora, você deve estar se perguntando:
“Como posso ler esse valor criptografado?”
Vamos ver como podemos fazer isso na próxima seção abaixo.

Leitura de um Campo Criptografado

Neste ponto, se nos conectarmos ao banco de dados sem passar a configuração de criptografia, não conseguiremos ler as informações.
  • 1. Para ler o campo, o cliente deve carregar a configuração de ClientSideFieldLevelEncryptionOptions em sua sessão. Isso envolve abrir uma conexão, carregar as opções em uma variável e usar o construtor Mongo(), semelhante ao que fizemos antes, mas, desta vez, sem a configuração de key vault:
(É por isso que é importante armazenar a chave em um local seguro, pois sua codificação será usada nas rotinas de leitura e escrita com criptografia.)  
  • 2. Com a configuração feita, podemos executar um find() para retornar o documento descriptografado:

Perguntas Comuns

1. Um usuário root pode ler os campos criptografados?
Não. O que determina se um usuário pode ler campos criptografados é se a conexão está carregada com a chave de criptografia usada. Sem ela, o usuário não conseguirá ler os campos, mesmo que tenha privilégios de root.
2. O que acontece se eu perder a chave?
Se a chave mestre do cliente for excluída ou perdida, todas as chaves de criptografia de dados relacionadas se tornam permanentemente ilegíveis. Isso faz com que todos os valores criptografados com essas chaves de dados também se tornem permanentemente inacessíveis.
3. Como isso funciona em um ReplicaSet ou Sharded Cluster?
O mesmo comportamento da seção “Leitura de um Campo Criptografado” se aplica a essas configurações. Uma vez que um documento com um campo criptografado é inserido, ele é replicado para os nós como está: criptografado. Apenas um usuário com a chave correta poderá ler o campo.
4. Existem limitações para o uso desse recurso?
Sim, conforme descrito no manual oficial. Existem limitações relacionadas a diferentes configurações, como Shard Key, Índices Únicos, Collation, Views, entre outros. É recomendável revisar o manual antes de qualquer implementação.  

Conclusão

Mesmo com a restrição ao uso da Criptografia Automática no Lado do Cliente, o método manual e o recurso em si mostraram ser uma opção interessante, principalmente porque fortalece a segurança ao permitir criptografar campos sensíveis no MongoDB, em vez de depender de ferramentas de terceiros. Isso ajuda a reduzir possíveis brechas de segurança que ferramentas externas podem criar. E se você tiver mais perguntas, sinta-se à vontade para compartilhá-las na seção de comentários abaixo.
Até mais!
Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *