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