Right to be forgotten: implementando exclusão de dados em sistemas
1. Fundamentos Legais e Conceituais
O direito ao esquecimento, consagrado no artigo 17 do GDPR (Regulamento Geral de Proteção de Dados da União Europeia) e no artigo 18 da LGPD brasileira, garante ao titular dos dados o direito de solicitar a exclusão de suas informações pessoais dos sistemas de um controlador. Este direito não é absoluto: existem exceções como cumprimento de obrigação legal, exercício de defesa em processos judiciais e interesse público.
Para o desenvolvedor, a distinção entre três conceitos é crucial:
- Anonimização: processo irreversível que impede a identificação do titular. Dados anonimizados não são mais considerados dados pessoais.
- Pseudonimização: substituição de identificadores diretos por pseudônimos, mantendo a possibilidade de reidentificação controlada.
- Exclusão física: remoção definitiva dos bits do armazenamento, sem possibilidade de recuperação.
A LGPD estabelece que o controlador (quem decide o tratamento) é o principal responsável por atender solicitações de exclusão, enquanto o operador (quem processa os dados) deve executar tecnicamente as ordens do controlador.
2. Desafios Técnicos na Exclusão de Dados
Dados em backups e logs
Backups e logs representam o maior desafio técnico. A política de retenção deve prever janelas de exclusão que respeitem o direito ao esquecimento sem comprometer a integridade do sistema. A abordagem recomendada é:
- Manter backups com ciclo de vida máximo definido (ex: 90 dias)
- Implementar exclusão diferida: dados marcados para exclusão em backups são removidos na próxima restauração ou rotação
- Para logs, utilizar anonimização automática após período de retenção legal
Referências cruzadas e chaves estrangeiras
A exclusão de um registro pode quebrar a integridade referencial do banco de dados. Estratégias incluem:
- Exclusão em cascata (CASCADE DELETE) para dependências diretas
- Atualização de chaves estrangeiras para NULL quando possível
- Criação de tabelas de histórico com referência ao ID do titular, que são limpas no mesmo processo
Sistemas legados e dados não estruturados
E-mails, documentos em servidores de arquivos e mensagens em sistemas legados frequentemente não possuem metadados de titularidade. A solução passa por:
- Implementar crawlers que varrem repositórios em busca de padrões de dados pessoais
- Criar APIs de integração para sistemas legados aceitarem comandos de exclusão
- Utilizar ferramentas de DLP (Data Loss Prevention) para mapear dados não estruturados
3. Estratégias de Implementação de Exclusão Lógica
Soft delete com timestamp de exclusão
A exclusão lógica é a abordagem mais segura para sistemas em produção. Consiste em marcar o registro como excluído sem removê-lo fisicamente do banco de dados principal.
-- Exemplo de tabela com soft delete
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY,
nome VARCHAR(100),
email VARCHAR(100) UNIQUE,
excluido_em TIMESTAMP NULL,
excluido_por VARCHAR(100),
motivo_exclusao TEXT,
data_expiracao_exclusao TIMESTAMP
);
-- Query para filtrar registros ativos
SELECT * FROM usuarios
WHERE excluido_em IS NULL;
Shadow tables para auditoria
Tabelas separadas mantêm um registro imutável das exclusões realizadas, servindo tanto para auditoria quanto para possível reversão controlada.
-- Tabela de auditoria de exclusão
CREATE TABLE auditoria_exclusoes (
id SERIAL PRIMARY KEY,
id_titular INTEGER NOT NULL,
dados_excluidos JSONB,
solicitado_em TIMESTAMP DEFAULT NOW(),
concluido_em TIMESTAMP,
hash_verificacao VARCHAR(64),
status VARCHAR(20) DEFAULT 'pendente'
);
Mecanismos de expurgo agendado
Dados marcados para exclusão com soft delete devem ser fisicamente removidos após um período de carência (ex: 30 dias), permitindo recuperação em caso de solicitação equivocada.
-- Cron job de expurgo (execução diária)
DELETE FROM usuarios
WHERE excluido_em IS NOT NULL
AND data_expiracao_exclusao < NOW();
4. Exclusão Física e Segurança da Informação
Sobrescrita segura
Excluir um arquivo apenas remove o ponteiro do sistema de arquivos, deixando os dados recuperáveis. Para dados sensíveis, utilize sobrescrita segura (shredding) que escreve padrões aleatórios sobre os setores do disco.
# Exemplo com ferramenta shred no Linux
shred -vfz -n 3 /caminho/para/arquivo_sensivel.csv
# -v: verbose (mostra progresso)
# -f: força permissões de escrita
# -z: adiciona uma passada com zeros ao final
# -n 3: número de passadas de sobrescrita
Gerenciamento de chaves criptográficas
Quando dados estão criptografados, a exclusão da chave de descriptografia é equivalente à exclusão dos dados, desde que a chave seja destruída de forma segura e irreversível.
-- Exemplo: destruição de chave em HSM (Hardware Security Module)
-- Comando conceitual para AWS KMS
aws kms schedule-key-deletion \
--key-id alias/minha-chave-usuarios \
--pending-window-in-days 7
Exclusão em ambientes cloud
Snapshots, réplicas e armazenamento redundante podem conter cópias dos dados mesmo após a exclusão do volume principal. É essencial:
- Identificar todos os recursos que armazenam dados do titular
- Utilizar políticas de ciclo de vida que expirem snapshots automaticamente
- Verificar se provedores de cloud oferecem garantias contratuais de exclusão (ex: AWS Glacier, Azure Blob Storage)
5. Implementação Prática com Exemplos de Código
Exemplo 1: Fluxo de exclusão com soft delete e auditoria
-- Função para exclusão com registro de auditoria
CREATE OR REPLACE FUNCTION solicitar_exclusao_usuario(
p_id_usuario INTEGER,
p_solicitante VARCHAR(100),
p_motivo TEXT
) RETURNS BOOLEAN AS $$
DECLARE
v_dados JSONB;
BEGIN
-- Captura dados atuais para auditoria
SELECT row_to_json(usuarios.*)::jsonb INTO v_dados
FROM usuarios WHERE id = p_id_usuario;
-- Insere registro na tabela de auditoria
INSERT INTO auditoria_exclusoes (
id_titular, dados_excluidos, solicitado_em, status
) VALUES (
p_id_usuario, v_dados, NOW(), 'pendente'
);
-- Marca como excluído logicamente
UPDATE usuarios SET
excluido_em = NOW(),
excluido_por = p_solicitante,
motivo_exclusao = p_motivo,
data_expiracao_exclusao = NOW() + INTERVAL '30 days'
WHERE id = p_id_usuario;
RETURN TRUE;
END;
$$ LANGUAGE plpgsql;
Exemplo 2: Exclusão em cascata com verificação de dependências
-- Função que verifica dependências antes de excluir
CREATE OR REPLACE FUNCTION excluir_usuario_completo(
p_id_usuario INTEGER
) RETURNS TABLE(tabela TEXT, registros_afetados INTEGER) AS $$
DECLARE
v_count INTEGER;
BEGIN
-- Verifica pedidos pendentes do usuário
SELECT COUNT(*) INTO v_count FROM pedidos
WHERE id_usuario = p_id_usuario AND status = 'pendente';
IF v_count > 0 THEN
RAISE EXCEPTION 'Usuário possui % pedidos pendentes', v_count;
END IF;
-- Exclui dados de endereços
DELETE FROM enderecos WHERE id_usuario = p_id_usuario;
GET DIAGNOSTICS v_count = ROW_COUNT;
RETURN QUERY SELECT 'enderecos'::TEXT, v_count;
-- Exclui dados de telefones
DELETE FROM telefones WHERE id_usuario = p_id_usuario;
GET DIAGNOSTICS v_count = ROW_COUNT;
RETURN QUERY SELECT 'telefones'::TEXT, v_count;
-- Anonimiza dados do usuário principal
UPDATE usuarios SET
nome = '[EXCLUIDO]',
email = CONCAT('excluido_', id, '@dominio.invalido'),
cpf = '[EXCLUIDO]'
WHERE id = p_id_usuario;
RETURN QUERY SELECT 'usuarios'::TEXT, 1;
END;
$$ LANGUAGE plpgsql;
Exemplo 3: Validação de identidade antes da exclusão
-- API de exclusão com autenticação forte
-- Pseudocódigo para validação em duas etapas
POST /api/v1/direito-esquecimento/solicitar
Headers:
Authorization: Bearer <token_acesso>
X-Idempotency-Key: <uuid_unico>
Body:
{
"motivo": "Revogação de consentimento",
"metodo_verificacao": "email_token",
"token_verificacao": "8f3a1b2c..."
}
-- Fluxo de validação:
-- 1. Verificar token de acesso (JWT com escopo de exclusão)
-- 2. Validar token de verificação enviado por e-mail/SMS
-- 3. Registrar solicitação com chave de idempotência
-- 4. Iniciar processo assíncrono de exclusão
-- 5. Retornar ID da solicitação para acompanhamento
6. Logs e Audit Trails Imutáveis para Exclusão
Registro de solicitações
Cada solicitação de exclusão deve gerar um registro imutável contendo:
-- Estrutura de log de solicitação de exclusão
CREATE TABLE logs_exclusao (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
id_titular_hash VARCHAR(64) NOT NULL, -- hash do ID do titular
data_solicitacao TIMESTAMP NOT NULL DEFAULT NOW(),
canal_solicitacao VARCHAR(50), -- web, email, suporte
status_processo VARCHAR(20), -- recebida, processando, concluida, falha
hash_anterior VARCHAR(64), -- hash do registro anterior (encadeamento)
hash_atual VARCHAR(64) -- SHA256 dos dados deste registro
);
Uso de hashes encadeados para integridade
-- Função que insere log com hash encadeado
CREATE OR REPLACE FUNCTION inserir_log_exclusao(
p_id_titular_hash VARCHAR(64),
p_canal VARCHAR(50),
p_status VARCHAR(20)
) RETURNS UUID AS $$
DECLARE
v_id UUID;
v_hash_anterior VARCHAR(64);
v_dados_para_hash TEXT;
BEGIN
-- Obtém o hash do último registro
SELECT hash_atual INTO v_hash_anterior
FROM logs_exclusao
ORDER BY data_solicitacao DESC
LIMIT 1;
-- Gera novo ID
v_id := gen_random_uuid();
-- Concatena dados para hash
v_dados_para_hash := CONCAT(
v_hash_anterior,
p_id_titular_hash,
p_canal,
p_status
);
-- Insere registro com hash encadeado
INSERT INTO logs_exclusao (
id, id_titular_hash, canal_solicitacao,
status_processo, hash_anterior, hash_atual
) VALUES (
v_id, p_id_titular_hash, p_canal,
p_status, v_hash_anterior,
encode(sha256(v_dados_para_hash::bytea), 'hex')
);
RETURN v_id;
END;
$$ LANGUAGE plpgsql;
7. Testes e Validação do Processo de Exclusão
Testes unitários para remoção em todas as tabelas
-- Teste: verificar se exclusão remove dados de todas as tabelas
BEGIN;
-- Executa exclusão
PERFORM excluir_usuario_completo(123);
-- Verifica tabelas de dados pessoais
ASSERT (SELECT COUNT(*) FROM enderecos WHERE id_usuario = 123) = 0,
'Endereços não foram excluídos';
ASSERT (SELECT COUNT(*) FROM telefones WHERE id_usuario = 123) = 0,
'Telefones não foram excluídos';
-- Verifica anonimização do registro principal
ASSERT (SELECT nome FROM usuarios WHERE id = 123) = '[EXCLUIDO]',
'Nome do usuário não foi anonimizado';
-- Verifica registro de auditoria
ASSERT (SELECT COUNT(*) FROM auditoria_exclusoes
WHERE id_titular = 123 AND status = 'concluido') > 0,
'Auditoria não registrou a exclusão';
ROLLBACK;
Testes de integração com sistemas de backup
-- Teste: verificar exclusão em ambiente com replicação
-- 1. Inserir dados de teste no banco primário
-- 2. Aguardar replicação para o secundário
-- 3. Executar exclusão no primário
-- 4. Verificar se dados também foram excluídos no secundário
-- 5. Restaurar snapshot de backup e verificar exclusão
8. Monitoramento Contínuo e Compliance
Métricas de SLA para exclusão
A LGPD não define prazo específico, mas o GDPR estabelece resposta em até 30 dias (prorrogável por mais 60). Estabeleça métricas internas mais rigorosas:
-- Métricas de SLA
-- Tempo médio para conclusão: < 24 horas
-- Tempo máximo para conclusão: < 72 horas
-- Percentual de solicitações dentro do SLA: > 99.5%
-- Taxa de falhas no processo de exclusão: < 0.1%
Alertas para falhas no processo
-- Consulta para detectar falhas no expurgo
SELECT COUNT(*) AS solicitacoes_pendentes,
MIN(data_solicitacao) AS mais_antiga
FROM auditoria_exclusoes
WHERE status = 'pendente'
AND data_solicitacao < NOW() - INTERVAL '48 hours';
Relatórios periódicos para auditoria
-- Relatório mensal de exclusões
SELECT
DATE_TRUNC('month', data_solicitacao) AS mes,
COUNT(*) AS total_solicitacoes,
COUNT(*) FILTER (WHERE status = 'concluido') AS concluidas,
COUNT(*) FILTER (WHERE status = 'falha') AS falhas,
ROUND(AVG(EXTRACT(EPOCH FROM (concluido_em - data_solicitacao)) / 3600), 2)
AS tempo_medio_horas
FROM auditoria_exclusoes
GROUP BY mes
ORDER BY mes DESC;
Implementar o direito ao esquecimento exige mais do que simples comandos DELETE. Requer um ecossistema que equilibre requisitos legais, integridade dos dados, segurança da informação e performance operacional. A combinação de exclusão lógica com expurgo físico agendado, logs imutáveis e testes rigorosos forma a base de um sistema compliant e resiliente.
Referências
-
LGPD - Lei Geral de Proteção de Dados (Lei 13.709/2018) — Texto oficial da lei brasileira com os artigos sobre direito à exclusão (Art. 18) e anonimização (Art. 12)
-
GDPR - Right to Erasure (Article 17) — Guia oficial do GDPR Europeu sobre o direito ao apagamento, incluindo exceções e procedimentos
-
NIST SP 800-88 Rev. 1: Guidelines for Media Sanitization — Padrão do NIST para sanitização segura de mídias, incluindo técnicas de sobrescrita e destruição física
-
AWS: Data Deletion and the Right to Be Forgotten — Whitepaper da AWS com estratégias práticas para implementar exclusão de dados em ambientes cloud
-
PostgreSQL Documentation: Row Security Policies and Deletion — Documentação oficial do PostgreSQL sobre políticas de segurança em nível de linha e estratégias de exclusão
-
OWASP: Data Protection Cheat Sheet — Guia de boas práticas do OWASP para proteção de dados, incluindo criptografia e exclus
ão segura
-
ISO/IEC 27001:2022 - Information Security Management — Norma internacional para gestão de segurança da informação, com controles aplicáveis à exclusão de dados e retenção segura
-
IETF RFC 3227 - Guidelines for Evidence Collection and Archiving — Diretrizes para coleta e arquivamento de evidências digitais, relevantes para logs de auditoria imutáveis
Sobre o autor:
Este artigo foi elaborado para a categoria Segurança para Devs, abordando aspectos práticos e legais da implementação do direito ao esquecimento em sistemas de software. A implementação correta desse direito não apenas evita sanções regulatórias, mas também fortalece a confiança dos usuários na plataforma.