Criptografia por campo: o que criptografar, chaves e migrações
A criptografia por campo ajuda a proteger dados sensíveis mantendo seu app utilizável. Aprenda o que criptografar, como gerenciar chaves e migrar com segurança.

Qual problema a criptografia por campo realmente resolve
Se alguém obtiver uma cópia do seu banco de dados, ele pode ler o que estiver em texto simples. Isso pode acontecer por um backup mal configurado, um laptop roubado com um dump do banco, uma ferramenta administrativa exposta ou um bug que vaze dados. Quando isso ocorre, o dano não é só “fomos hackeados.” É “todo registro de usuário está legível.”
A criptografia por campo reduz o raio de impacto. Em vez de confiar apenas na proteção do disco ou da rede, você protege valores específicos dentro do banco para que não sejam legíveis sem a chave correta. Se um atacante pegar linhas do banco, os campos criptografados parecem nonsense.
Ajuda separar as camadas:
- TLS protege os dados enquanto viajam entre sua aplicação e o banco.
- Criptografia de disco protege o dispositivo de armazenamento quando está offline.
- Criptografia por campo protege colunas específicas mesmo se o conteúdo do banco for copiado.
O tradeoff é real: uma vez que você criptografa um campo, o banco não consegue facilmente pesquisar, ordenar ou agrupar por ele. Relatórios, filtros e recursos de “encontrar usuário por X” podem precisar de mudanças. Muitas equipes mantêm um valor de busca limitado (como um hash com chave do e-mail) para preservar consultas comuns sem armazenar o valor subjacente em texto simples.
A criptografia por campo costuma perseguir alguns objetivos concretos: limitar o que um dump vazado pode revelar, atender expectativas de privacidade para dados sensíveis, reduzir danos downstream (roubo de identidade, golpes direcionados) e diminuir risco de acesso interno, especialmente em bases de código compartilhadas ou bagunçadas.
Decidindo o que criptografar (e o que não criptografar)
A criptografia por campo vale o esforço apenas para dados que causariam dano real se expostos. Uma definição simples de “sensível” é: se alguém conseguisse uma cópia do banco, o que ajudaria essa pessoa a roubar dinheiro, tomar contas, chantagear usuários ou quebrar promessas de privacidade?
Comece listando os poucos campos que são verdadeiramente perigosos em texto simples. Exemplos comuns incluem documentos governamentais (como SSNs), data de nascimento, tokens de API, códigos de reset ou recuperação, notas privadas e qualquer coisa que permita a um atacante agir como um usuário ou acessar um serviço de terceiros.
Muitos campos geralmente não precisam de criptografia porque são necessários para o funcionamento básico e têm baixo impacto por si só: IDs internas e chaves estrangeiras, timestamps (created_at, last_login), booleanos e flags de status, campos de perfil público (display name, bio) e metadados não sensíveis usados para ordenação e filtros.
Em seguida, decida quem precisa ler o texto simples. Alguns campos devem ser legíveis apenas pela sua aplicação em tempo de execução (por exemplo, um token de API usado para chamar um provedor). Outros podem precisar de acesso controlado pela equipe de suporte (padrão “ver últimos 4 dígitos”). E alguns devem ser legíveis apenas pelo usuário, o que muitas vezes significa criptografar em repouso e limitar onde a descriptografia pode ocorrer.
Comprometa-se a começar pequeno. Criptografar “tudo só por precaução” quebra busca, relatórios e integrações, e torna migrações mais difíceis depois.
Escolhendo uma abordagem que se encaixe nas necessidades do seu app
Não existe uma única “melhor” maneira de fazer criptografia por campo. A abordagem certa depende do que seu app ainda precisa fazer com os dados após serem protegidos: buscas, exports, ferramentas de suporte e auditorias.
Se você só precisa ler o valor depois (por exemplo, mostrar ao usuário o CPF salvo), use criptografia aleatória (não determinística). É mais segura porque a mesma entrada não produz o mesmo texto cifrado cada vez. A desvantagem é que você não pode fazer buscas por igualdade na coluna criptografada.
Se você precisa fazer buscas por igualdade (como “encontrar usuário por SSN” ou “detectar conta bancária duplicada”), a criptografia determinística é tentadora porque suporta igualdade. Mas ela vaza padrões (mesmo valor gera mesmo ciphertext). Uma opção mais segura em muitos casos é manter o valor criptografado e armazenar um hash com chave separado para buscas.
Use criptografia autenticada, não apenas “só criptografar”. Sem autenticação, a aplicação pode não detectar adulteração. Com um modo autenticado (frequentemente chamado AEAD), a aplicação consegue saber se o ciphertext foi alterado.
Para o manejo de chaves, envelope encryption costuma ser um meio-termo prático. Você encripta o campo com uma chave de dados (DEK) e depois embrulha essa DEK com uma chave mestre (KEK). Você pode fazer isso por registro ou por tenant. Chaves por tenant limitam o raio de impacto em apps multitenant e tornam o offboarding mais limpo.
Quando você não precisa do texto simples de volta, não criptografe. Em vez disso, faça hash. Senhas são o caso clássico: armazene um hash de senha lento, não a senha criptografada.
A tokenização ajuda quando partes do seu fluxo não conseguem lidar com ciphertext (ferramentas legadas, dashboards de suporte, exports para terceiros). Você substitui o valor sensível por um token e mantém o valor real em uma loja separada e bem protegida.
Um resumo rápido para escolher:
- Precisa mostrar o valor depois: criptografia aleatória com autenticação.
- Precisa de busca por igualdade: valor criptografado + índice por hash com chave (ou criptografia determinística com cuidado).
- Precisa de isolamento por tenant: envelope encryption com chaves embrulhadas por tenant.
- Nunca precisa do texto simples: hashing.
- Fluxos quebram com ciphertext: tokenização.
Noções básicas de gerenciamento de chaves, sem jargão
A criptografia por campo é tão segura quanto suas chaves. O objetivo é simples: sua aplicação consegue descriptografar quando realmente precisa, mas as chaves ficam protegidas em outro lugar, com regras de acesso restritas e registros confiáveis.
Um modelo mental útil é “separar responsabilidades.” Seu banco armazena ciphertext (dados trancados). Sua aplicação solicita criptografia/descriptografia quando permitido. Um sistema de chaves guarda as chaves e decide quem pode usá-las.
Onde as chaves devem ficar
Para a maioria das equipes, o padrão mais seguro é um serviço de chaves gerenciado, não uma solução caseira. Opções comuns são um KMS na nuvem, um serviço com HSM ou um gerenciador de segredos que forneça a chave em tempo de execução.
Evite as falhas comuns:
- Não armazene chaves de criptografia no banco.
- Não comite chaves no repositório.
- Não mantenha chaves em arquivos de ambiente compartilhados que muitas pessoas e sistemas podem ler.
- Não reutilize a mesma chave entre dev, staging e produção.
Um exemplo prático de acesso: se uma ferramenta de suporte pode ver perfis mascarados de usuários, ela não deveria conseguir descriptografar valores completos. Apenas a API principal que serve usuários autenticados deve ter permissão de descriptografar em produção.
Acesso e logs (para você poder provar o que aconteceu)
O acesso às chaves deve ser explícito e mínimo. Defina quais serviços podem descriptografar quais campos, em quais ambientes e sob qual identidade (conta de serviço ou papel). Se um job em background só precisa encriptar ao gravar, talvez não precise de privilégios de descriptografia.
Planeje auditorias desde cedo. Você vai querer logs de uso de chaves que respondam “quem usou qual chave, quando e de onde.” Isso possibilita investigações e ajuda a detectar erros como um serviço de teste chamando chaves de produção.
Rotação e versionamento de chaves que você precisará depois
Criptografia por campo não é “configura e esquece”. Planeje rotação de chaves desde o início, ou você ficará preso a chaves arriscadas que não dá para mudar sem downtime.
Primeiro, decida a unidade das chaves. Uma única chave para todo o app é a mais simples, mas amplia qualquer incidente. Chaves por tenant limitam o impacto em SaaS. Chaves por usuário podem esclarecer regras de acesso, mas adicionam complexidade quando usuários compartilham dados. Chaves por registro são raras, salvo motivos fortes.
Seja qual for a escolha, armazene um identificador de chave junto a cada valor criptografado. Pode ser um rótulo curto de versão (como v3) ou um key ID. O importante é que a descriptografia consiga olhar o ciphertext, ver qual versão de chave foi usada e selecionar a chave certa sem adivinhações.
Uma configuração prática de rotação geralmente tem duas camadas:
- Uma chave de encriptação de dados (DEK) usada para criptografar os campos.
- Uma chave mestre (KEK) usada para embrulhar (encriptar) a DEK.
Com essa abordagem, você pode rotacionar a chave mestre sem reescrever todos os dados criptografados. Você apenas reembrulha a DEK, o que é rápido.
Às vezes é preciso recriptografar os dados reais: se uma DEK foi exposta, se você muda algoritmos ou parâmetros, ou se políticas exigirem outro escopo de chave (por exemplo, mudar de uma chave por app para chaves por tenant).
Não pule backups e recuperação para chaves. Perder chaves significa perder dados. Mantenha backups das chaves cifrados, restrinja acesso e teste restauras periodicamente. Um modo comum de falha é “fizemos backup do banco, mas não das chaves.”
Exemplo: uma startup rotaciona de v1 para v2. Escritas novas usam v2, linhas antigas mantêm v1, e um job em background recriptografa gradualmentes as antigas.
Como adicionar criptografia por campo passo a passo
Trate isso como uma mudança no modelo de dados, não como um “patch de segurança rápido”. Um rollout cuidadoso evita que você vaze texto simples em logs, exports ou scripts administrativos pontuais.
Comece mapeando o que é realmente sensível e por onde ele trafega. Não olhe apenas o banco. Trace create, read, update, jobs em background, analytics e exports. Um erro comum é criptografar uma coluna e esquecer o job de CSV export, que vira o novo vazamento.
Escolha uma biblioteca de criptografia comprovada para sua stack e um esquema de criptografia que você consiga explicar para o seu eu do futuro. Para a maioria dos apps, criptografia autenticada é o padrão certo. Mantenha chaves fora do banco e planeje versionamento desde o dia um.
Um rollout que costuma funcionar:
- Adicione colunas criptografadas novas ao lado das antigas em texto simples e faça primeiro essa mudança de esquema.
- Adicione um wrapper pequeno que faça encrypt-on-write e decrypt-on-read, e faça o resto da aplicação chamar só essa camada.
- Pare de gravar texto simples assim que for seguro, mas mantenha leituras em texto simples por pouco tempo para a transição.
- Backfill as linhas existentes em lotes, com monitoramento, limites de taxa e um plano de rollback.
- Verifique com queries e exports reais, então remova campos em texto simples em uma migração posterior.
Durante o backfill, evite imprimir valores descriptografados em logs, relatórios de erro ou dashboards administrativos. Logue IDs de registros e contagens de status em vez disso.
Mantendo funcionalidades: busca, relatórios e desempenho
A criptografia por campo protege valores sensíveis, mas pode quebrar funcionalidades do dia a dia se você não planejar. Antes de criptografar colunas, liste quais telas e jobs dependem desses campos: caixas de busca, tabelas admin, exports e relatórios agendados.
Busca e filtros
Com criptografia aleatória (não determinística), a mesma entrada é cifrada de modo diferente a cada vez. Buscas por igualdade e deduplicação param de funcionar porque o banco não consegue comparar ciphertext. Se você precisa de busca por igualdade (como buscar usuário por SSN), armazene um token de busca separado ao lado do valor criptografado, por exemplo um hash com chave.
Busca por parcial (contains, starts-with) geralmente não pode ser suportada com segurança em texto criptografado sem sistemas especiais, então a maioria das equipes remove esse tipo de busca para campos sensíveis.
Ordenação e consultas por intervalo também costumam quebrar. Ciphertext não tem ordem significativa, então você não consegue ordenar por “salário” ou filtrar “data de nascimento entre X e Y” diretamente. Uma solução comum é armazenar um derivado grosseiro (como mês e ano) ou buckets pré-computados.
Relatórios, indexação, cache e velocidade
Para analytics, planeje um dataset separado: agregados, contadores ou uma cópia redigida que exclua campos sensíveis.
Algumas regras práticas que funcionam bem:
- Indexe hashes ou hashes com chave, não valores descriptografados.
- Não faça cache de dados descriptografados em caches compartilhados ou logs.
- Descriptografe o mais tarde possível (logo antes do uso).
- Meça caminhos quentes, porque descriptografar em loops apertados pode adicionar latência.
Migrações sem expor texto simples
Assuma que seu banco ficará em estado misto por um tempo. Algumas linhas terão texto simples, outras terão ciphertext, e outras podem usar versões diferentes de chaves. Seu código deve lidar com todos esses casos sem que ninguém precise rodar um script pontual que despeje texto simples em logs ou arquivos temporários.
Um padrão comum é dual-read: quando sua aplicação carrega um valor, ela tenta o campo criptografado primeiro. Se estiver vazio, cai de volta no campo legado em texto simples. Isso mantém dados antigos funcionando enquanto você migra em background.
Combine isso com dual-write: quando a aplicação salva um valor, ela grava a forma criptografada e, por um curto período de transição, mantém o campo antigo em texto simples atualizado. Isso evita que novos registros sejam criados no formato antigo enquanto você está convertendo os registros antigos.
Para o backfill, rode um job em background que encripta linhas legadas em pequenos lotes. Trate isso como um sistema de produção: limite a taxa de updates, use retries e escritas idempotentes (seguras para rodar duas vezes), registre progresso, espere falhas parciais e armazene a versão da chave junto ao ciphertext.
Exemplo: uma tabela de signups tinha phone_plain e você adiciona phone_enc mais phone_key_version. Novos cadastros gravam phone_enc. O job caminha pelos usuários antigos, encripta phone_plain, seta a versão e deixa o texto simples até você verificar leituras, exports e ferramentas de suporte.
Só delete o texto simples legado após um corte claro: métricas mostram cobertura criptografada quase 100%, dual-read rodou em produção tempo suficiente e você tem um plano de rollback.
Erros comuns e armadilhas a evitar
A criptografia por campo é fácil de demonstrar no caminho feliz. O problema aparece depois: durante outages, migrações, exports ou fluxos de suporte.
As armadilhas que vazam dados (mesmo se você criptografar)
A maioria dos vazamentos não vem do banco. Vem de tudo ao redor: logs, exports, dashboards, endpoints de debug e ferramentas de terceiros.
Modos comuns de falha incluem texto simples em logs (prints de depuração, dumps de requisição, traces de exceção), chaves hardcoded ou chaves no lado do cliente (apps móveis, bundles de browser, segredos comitados no git), falta de detecção de adulteração (sem criptografia autenticada), saídas esquecidas (CSV exports, recibos por email, payloads de webhooks, telas admin) e restores sem teste (backups existem, mas as chaves estão faltando ou a versão da chave é desconhecida).
Um exemplo concreto: um app encripta SSNs, mas um erro 500 loga o corpo da requisição inteiro para ajudar o debugging. O banco está seguro, mas os logs viram um banco sombra em texto simples.
Criptografar os campos errados
Um erro comum é criptografar campos dos quais sua aplicação depende para joins, checagens de unicidade ou fluxos de suporte. Se você criptografar um e-mail, pode quebrar buscas de login, deduplicação e “encontrar cliente” nas ferramentas admin. Se ainda precisar de checagens de igualdade, provavelmente precisará de um valor derivado (como um hash com chave) ou de um desenho diferente.
Antes de enviar, faça um rápido “para onde esse valor vai?”: queries de banco, logs, exports, e-mails, analytics e ferramentas de suporte.
Por fim, trate recuperação de chaves como um recurso. Dados criptografados sem chaves são perda de dados permanente.
Checklist rápido antes de enviar
A criptografia por campo costuma falhar por motivos banais: um campo é copiado para algum lugar, ou um job grava texto simples “só desta vez”. Antes do release, faça uma última varredura focada em onde os dados podem vazar.
- Mapeie todos os lugares onde o valor sensível pode aparecer: colunas do banco, logs da aplicação, eventos analíticos, relatórios de erro, caches, índices de busca e backups.
- Confirme que texto simples nunca é escrito “temporariamente”: sem logs de depuração, sem exportações de arquivo e sem arquivos temporários no disco.
- Armazene informações de versão com o ciphertext: versão da chave (e idealmente uma tag de algoritmo/versão) para que você consiga descriptografar registros antigos após mudanças.
- Prove que você consegue rotacionar chaves sem downtime: leia dados antigos, escreva novos dados com a chave nova e recriptografe em background.
- Aplique princípio de menor privilégio para descriptografia: apenas o conjunto mínimo de serviços e papéis que realmente precisam do texto simples devem ter acesso.
Verifique que você tem um procedimento testado de backup e restauração tanto para dados quanto para chaves, e que ele funciona sob pressão (novo ambiente, nova máquina, nova pessoa executando).
Exemplo: criptografando alguns campos em um app real
Uma pequena startup guarda CPFs dos clientes e notas internas de suporte em uma tabela customers. O app começou como protótipo e tem um hábito ruim: quando ocorre um erro, ele loga o registro inteiro “para debugar.” Isso significa que CPFs e notas privadas podem acabar em logs, dashboards ou ferramentas de erro de terceiros.
Eles escolhem criptografar por campo duas colunas: tax_id e support_notes. Todo o resto fica em texto simples para que o app ainda possa filtrar, ordenar e gerar relatórios sem trabalho extra.
Para manter o suporte rápido, eles adicionam uma coluna separada como tax_id_hash (um hash unidirecional com chave). O suporte pode fazer buscas por igualdade (um cliente liga e informa o CPF), mas o banco nunca armazena esse CPF pesquisável em texto simples. A aplicação compara hasheando a entrada e casando o hash.
O plano de rollout mantém o app funcionando enquanto os dados ainda são convertidos:
- Adicionar colunas criptografadas novas (ou novas versões
_enc) e um campokey_version. - Dual-write: salvar tanto o texto simples antigo quanto o valor criptografado por um curto período.
- Dual-read: preferir o valor criptografado; recorrer ao texto simples se faltar.
- Backfill em lotes com alertas se ocorrer falha na descriptografia ou se um registro parecer malformado.
- Quando a cobertura estiver perto de 100%, pare de gravar texto simples e remova-o numa migração posterior.
Depois da mudança, logs de erro contêm placeholders redigidos em vez de segredos completos. A equipe de suporte só vê notas descriptografadas se o papel deles permitir.
Próximos passos se você estiver atualizando uma base de código existente
Atualizar um app existente é onde a criptografia por campo fica bagunçada. O objetivo é avançar sem criar uma janela longa onde dados sensíveis ficam expostos, copiados para logs ou silenciosamente regravados em texto simples.
Comece com um registro de decisão curto que sua equipe possa compartilhar. Mantenha numa página: quais campos serão criptografados, por quê (legal, risco, confiança do cliente) e quais sistemas ou papéis podem descriptografar. Isso evita mudanças aleatórias de “criptografar tudo” que quebram funcionalidades depois.
Comece com um piloto pequeno que você entenda completamente: uma tabela, um fluxo de usuário, um caminho de migração. Criptografe algo como SSN ou número de conta bancária em uma tabela cliente e atualize apenas as telas de “ver perfil” e “atualizar perfil”. Você encontrará rapidamente onde o texto simples vaza hoje (logs de debug, exports, trackers de erro) antes de escalar para mais campos.
Adicione guardrails antes do rollout:
- Pare de logar segredos (uma regra simples: nunca logar corpos de requisição).
- Torne erros seguros (sem stack traces ou valores descriptografados em mensagens visíveis ao usuário).
- Revise acesso (quem pode rodar exports, quem pode consultar produção, o que vai para analytics).
- Adicione testes que falhem se texto simples for armazenado ou retornado.
Se você herdou um código gerado por IA, faça uma revisão de segurança focada antes de migrar. Esses projetos frequentemente têm segredos expostos, permissões excessivas e logs “úteis” que imprimem tudo.
Se precisar de ajuda externa para limpar um app gerado por IA antes de adicionar criptografia, FixMyMess (fixmymess.ai) foca em diagnosticar e reparar bases de código assim, incluindo hardening e migrações seguras, para que você não coloque criptografia por cima de vazamentos existentes.
Perguntas Frequentes
Do que a criptografia por campo realmente me protege?
Protege valores específicos dentro das suas tabelas para que um dump do banco não revele esses campos em texto simples. É principalmente para cenários “alguém pegou as linhas”, não para evitar ataques ao app em execução.
Quais campos devo criptografar primeiro?
Comece por campos que causariam dano real se expostos, como IDs governamentais, data de nascimento, códigos de recuperação, tokens de API ou notas privadas. Deixe metadados de rotina (IDs, timestamps, flags de status) sem criptografia para que o app continue consultando e gerando relatórios normalmente.
Devo usar criptografia aleatória (não determinística) ou determinística?
A criptografia aleatória (não determinística) é o padrão mais seguro quando você só precisa ler o valor depois, porque entradas idênticas não geram o mesmo texto cifrado. O custo é que normalmente não dá para fazer buscas por igualdade nessa coluna cifrada.
Como ainda encontro um usuário por um valor sensível se ele estiver criptografado?
Mantenha o valor sensível criptografado e adicione um valor de busca separado, como um hash com chave, para buscas por igualdade. Assim você busca por correspondência sem armazenar o valor original em texto pesquisável.
Preciso de criptografia autenticada ou só criptografar já basta?
Use criptografia autenticada (frequentemente chamada AEAD) para que sua aplicação detecte se o texto cifrado foi alterado. Abordagens apenas de “criptografar” podem permitir que dados adulterados passem despercebidos e causem falhas ou problemas na descriptografia.
Onde devem ficar as chaves de criptografia?
Mantenha as chaves fora do banco e fora do repositório, e prefira um sistema de chaves gerenciado (como um KMS na nuvem ou um gerenciador de segredos) para controlar o acesso. Um bom padrão é que apenas o serviço principal de produção que realmente precisa do texto simples tenha permissão de descriptografar.
Como faço rotação de chaves sem downtime?
Armazene um identificador de chave (uma versão ou ID de chave) junto a cada valor criptografado para que você consiga descriptografar dados antigos após mudanças. Uma abordagem comum é envelope encryption, assim você pode rotacionar a chave mestre sem reescrever todos os campos criptografados.
Qual a forma mais segura de migrar dados existentes em texto simples para campos criptografados?
Trate isso como uma mudança no modelo de dados: adicione novas colunas criptografadas, passe a gravar criptografado e faça backfill das linhas antigas em lotes. Durante a transição, as leituras preferem o valor criptografado e recorrem ao texto simples apenas quando necessário; só remova o texto simples após verificar exports e ferramentas.
Quais são as maneiras mais comuns de vazar texto simples mesmo depois de criptografar campos?
A maioria dos vazamentos não vem do banco. Pare o texto simples em logs, relatórios de erro, exportações, telas administrativas e eventos analíticos. Também evite prints de depuração “temporários” durante backfills, pois isso cria uma cópia sombra dos dados sensíveis.
E se meu código for bagunçado (ou gerado por IA) e eu temer que a criptografia vá quebrar coisas?
Se você herdou um código bagunçado ou gerado por IA, corrija logs de segredos e controles de acesso antes de adicionar criptografia, porque criptografia não ajuda se o texto simples já está vazando para logs e exportações. FixMyMess pode fazer uma auditoria de código gratuita e depois reparar e endurecer o app para que mudanças de criptografia não fiquem apoiadas sobre vazamentos existentes, com a maioria das correções concluídas em 48–72 horas.