LGPD para desenvolvedores: implementando privacidade no código
1. Fundamentos da LGPD no contexto do desenvolvimento
A Lei Geral de Proteção de Dados (LGPD) estabelece que a privacidade deve ser incorporada desde a concepção dos sistemas. Para desenvolvedores, isso significa traduzir princípios legais em decisões técnicas concretas.
Princípios essenciais aplicados ao código:
- Finalidade: Cada coleta de dado deve ter uma justificativa documentada no código. Exemplo: um campo de CPF só deve existir se houver obrigação fiscal.
- Necessidade: Implementar verificações que impeçam a coleta de dados excessivos. O princípio da minimização deve estar embutido nas validações de formulário.
- Transparência: Logs de processamento devem registrar explicitamente qual base legal está sendo utilizada.
Mapeamento de dados pessoais:
Todo desenvolvedor precisa identificar onde os PII (Personally Identifiable Information) trafegam no sistema. Um inventário simples pode ser mantido como comentários estruturados:
// Fluxo: Cadastro de usuário
// Dados coletados: nome, email, CPF (obrigatório fiscal)
// Base legal: consentimento (art. 7º, I) e obrigação legal (art. 7º, II)
// Retenção: 5 anos após encerramento da conta
Papéis na prática:
- Controlador: quem define as finalidades (geralmente o product owner)
- Operador: quem processa os dados (desenvolvedores e equipe de infra)
- Encarregado (DPO): ponto de contato para titulares e ANPD
O desenvolvedor atua como operador, mas precisa entender as decisões do controlador para implementar corretamente as restrições.
2. Minimização de dados desde o design
A minimização é o princípio mais impactante no código. Cada campo desnecessário é um risco jurídico.
Coleta seletiva:
// Exemplo de formulário com campos mínimos
<form id="cadastro">
<input type="text" name="nome" required>
<input type="email" name="email" required>
<!-- CPF removido - não é necessário para este serviço -->
<!-- data de nascimento removida - não há justificativa -->
<button type="submit">Cadastrar</button>
</form>
Pseudonimização com hash:
import hashlib
def pseudonimizar_email(email):
# SHA-256 com salt fixo por segurança
salt = "constante_do_sistema_2024"
hash_obj = hashlib.sha256((email + salt).encode())
return hash_obj.hexdigest()[:16] # Truncado para reduzir risco
Anonimização por generalização:
// Em vez de armazenar "1990-05-15", armazenar apenas o ano
function generalizarData(dataNascimento) {
return dataNascimento.split('-')[0] + "-01-01";
}
// Resultado: 1990-01-01 (apenas ano preservado)
Política de retenção automática:
// Job agendado para deletar logs de acesso após 90 dias
DELETE FROM logs_acesso
WHERE data_criacao < DATE_SUB(NOW(), INTERVAL 90 DAY);
3. Consentimento e transparência no código
O consentimento deve ser explícito, granular e rastreável.
Mecanismo de consentimento granular:
<div class="consentimento">
<label>
<input type="checkbox" name="consent_email" data-finalidade="marketing">
Receber newsletter semanal
</label>
<label>
<input type="checkbox" name="consent_analytics" data-finalidade="melhoria">
Permitir coleta de dados de uso
</label>
</div>
Registro de consentimento com timestamp:
// Estrutura de tabela para logs de consentimento
CREATE TABLE logs_consentimento (
id INT AUTO_INCREMENT PRIMARY KEY,
usuario_id INT NOT NULL,
finalidade VARCHAR(100) NOT NULL,
aceito BOOLEAN NOT NULL,
versao_politica VARCHAR(20) NOT NULL,
ip_origem VARCHAR(45),
data_criacao TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (usuario_id) REFERENCES usuarios(id)
);
Implementação de banner com rastreamento:
// Banner de cookies com controle de estado
const bannerLGPD = {
exibir: function() {
if (!localStorage.getItem('consentimento_exibido')) {
document.getElementById('banner-lgpd').style.display = 'block';
}
},
aceitarTodos: function() {
localStorage.setItem('consentimento_exibido', 'true');
localStorage.setItem('consentimento_marketing', 'true');
localStorage.setItem('consentimento_analytics', 'true');
document.getElementById('banner-lgpd').style.display = 'none';
// Enviar para o servidor
fetch('/api/consentimento', {
method: 'POST',
body: JSON.stringify({
aceito: true,
finalidades: ['marketing', 'analytics'],
versao: 'v1.2'
})
});
}
};
4. Controle de acesso e segurança de dados pessoais
RBAC aplicado a dados sensíveis:
// Middleware de autorização para dados sensíveis
function autorizarAcessoDadosSensiveis(req, res, next) {
const usuario = req.usuario;
const dadosSensiveis = ['cpf', 'rg', 'dados_medicos'];
if (dadosSensiveis.includes(req.params.tipo)) {
if (usuario.role !== 'admin' && usuario.role !== 'dpo') {
return res.status(403).json({ erro: 'Acesso negado a dados sensíveis' });
}
}
next();
}
Criptografia em repouso (banco de dados):
-- Criptografia AES-256 para colunas sensíveis
ALTER TABLE usuarios
ADD COLUMN cpf_criptografado VARBINARY(256);
-- Inserção com criptografia
INSERT INTO usuarios (cpf_criptografado)
VALUES (AES_ENCRYPT('123.456.789-00', 'chave_secreta_32bytes'));
Auditoria de acessos:
// Trigger para registrar consultas a dados sensíveis
CREATE TRIGGER auditoria_consulta_cpf
BEFORE SELECT ON usuarios
FOR EACH ROW
BEGIN
INSERT INTO logs_acesso_dados (
usuario_id,
acao,
tabela,
coluna,
data_acesso
) VALUES (
CURRENT_USER(),
'CONSULTA',
'usuarios',
'cpf',
NOW()
);
END;
5. Direitos dos titulares automatizados
API de portabilidade:
// Endpoint para exportação de dados
app.get('/api/portabilidade/:usuarioId', async (req, res) => {
const dados = await Usuario.findById(req.params.usuarioId)
.select('-senha -token_recuperacao');
res.setHeader('Content-Type', 'application/json');
res.setHeader('Content-Disposition', 'attachment; filename=dados_pessoais.json');
res.json({
versao: '1.0',
data_exportacao: new Date().toISOString(),
dados: dados
});
});
Endpoint de exclusão com verificação:
// Soft delete com verificação de dependências
app.delete('/api/usuario/:id', async (req, res) => {
const dependencias = await verificarDependencias(req.params.id);
if (dependencias.length > 0) {
return res.status(409).json({
erro: 'Não é possível excluir. Dependências ativas:',
dependencias: dependencias
});
}
// Soft delete - marca como inativo
await Usuario.updateOne(
{ _id: req.params.id },
{ $set: {
status: 'excluido',
data_exclusao: new Date(),
motivo: req.body.motivo
}}
);
res.json({ mensagem: 'Solicitação de exclusão registrada' });
});
6. Tratamento de incidentes e notificação
Detecção de anomalias:
// Monitoramento de acessos suspeitos
app.use((req, res, next) => {
const acessosPorIP = registrarAcesso(req.ip);
if (acessosPorIP > 100) { // Mais de 100 requisições por minuto
alertaVazamento({
tipo: 'ACESSO_SUSPEITO',
ip: req.ip,
rota: req.path,
timestamp: new Date()
});
}
next();
});
Workflow de notificação automática:
function notificarIncidente(dadosVazados, usuariosAfetados) {
// Disparar email para DPO
enviarEmail('dpo@empresa.com', {
assunto: 'Incidente de segurança detectado',
corpo: `Foram identificados ${usuariosAfetados} registros comprometidos`
});
// Registrar no sistema de compliance
fetch('https://api.anpd.gov.br/notificacao', {
method: 'POST',
body: JSON.stringify({
data_incidente: new Date(),
natureza: dadosVazados.includes('senha') ? 'ALTA' : 'MEDIA',
medidas_tomadas: ['revogacao_tokens', 'isolamento_servidor']
})
});
}
7. Testes e compliance contínuo
Testes automatizados de privacidade:
describe('Testes de privacidade', () => {
it('deve negar acesso a dados sem consentimento', async () => {
const response = await request(app)
.get('/api/dados-sensiveis')
.set('Authorization', 'Bearer token_sem_consentimento');
expect(response.status).toBe(403);
expect(response.body.erro).toContain('consentimento');
});
it('deve excluir dados após período de retenção', async () => {
const usuarioAntigo = await criarUsuario({ data_criacao: '2019-01-01' });
await executarJobRetencao();
const usuario = await Usuario.findById(usuarioAntigo._id);
expect(usuario).toBeNull();
});
});
Documentação técnica (ROPA automático):
// Script para gerar registro de operações
function gerarROPA() {
const operacoes = [];
// Mapear todas as rotas que manipulam dados pessoais
app._router.stack.forEach((middleware) => {
if (middleware.route) {
const rota = middleware.route;
if (rota.path.includes('usuario') || rota.path.includes('dados')) {
operacoes.push({
rota: rota.path,
metodos: Object.keys(rota.methods),
dados: extrairCampos(rota),
baseLegal: rota.baseLegal || 'consentimento'
});
}
}
});
fs.writeFileSync('ropa.json', JSON.stringify(operacoes, null, 2));
}
Implementar a LGPD no código não é apenas uma obrigação legal, mas uma oportunidade de construir sistemas mais confiáveis e éticos. Cada linha de código deve refletir o respeito pela privacidade dos usuários, desde a coleta mínima de dados até a garantia de seus direitos.
Referências
- Lei Geral de Proteção de Dados Pessoais (LGPD) - Lei nº 13.709/2018 — Texto oficial da lei que estabelece as regras de proteção de dados no Brasil.
- Guia de Boas Práticas da ANPD para Desenvolvedores — Documento da Autoridade Nacional de Proteção de Dados com orientações técnicas.
- OWASP Top 10 para Privacidade — Lista dos principais riscos de privacidade em aplicações web, com exemplos de mitigação.
- Documentação oficial do MongoDB sobre criptografia de dados — Guia prático para implementar criptografia em repouso em bancos NoSQL.
- Tutorial de RBAC com Node.js e Express — Implementação passo a passo de controle de acesso baseado em funções.
- Guia da ICO (Information Commissioner's Office) sobre Privacy by Design — Referência internacional sobre incorporar privacidade desde o design.