Logging de segurança: o que registrar sem expor dados sensíveis

1. Por que o Logging de Segurança é Crítico (e Perigoso)

O logging é uma das práticas mais subestimadas no desenvolvimento de software. Ele fornece visibilidade sobre o comportamento do sistema, auxilia na depuração de erros e é essencial para investigações forenses após incidentes de segurança. No entanto, essa mesma visibilidade pode se tornar um pesadelo de privacidade se não for cuidadosamente controlada.

O dilema do desenvolvedor é claro: quanto mais informações registramos, mais fácil é entender e depurar problemas — mas também maior é o risco de expor dados sensíveis. Logs mal configurados já causaram vazamentos massivos de informações em empresas como a Uber (2016), onde credenciais de acesso à nuvem foram expostas em logs públicos, e a Twilio (2022), que sofreu um ataque de engenharia social após credenciais vazarem em logs internos.

Sob a ótica da LGPD e do GDPR, um log que contenha dados pessoais sem anonimização adequada pode configurar violação de dados, sujeitando a empresa a multas de até 4% do faturamento global. Para o desenvolvedor, o risco inclui desde demissão por justa causa até responsabilização criminal em casos de vazamento doloso.

2. Dados que NUNCA Devem Ser Registrados

Existem categorias de informação que jamais devem aparecer em logs, independentemente do nível de acesso ou do ambiente (desenvolvimento, homologação ou produção):

  • Informações de autenticação: senhas em texto claro, tokens JWT, chaves de API, secrets de OAuth
  • Dados pessoais identificáveis (PII): CPF, RG, e-mail completo, endereço residencial, número de telefone
  • Dados financeiros: números completos de cartão de crédito, CVV, dados bancários
  • Dados biométricos: impressões digitais, reconhecimento facial, padrões de voz
  • Informações de saúde: diagnósticos, exames, prontuários

Exemplo de log proibido vs. log seguro:

# ❌ PROIBIDO - NUNCA faça isso
log.info("Usuário autenticado: joao.silva@email.com, senha: MinhaSenha123!, token: eyJhbGciOiJIUzI1NiIs...")

# ✅ SEGURO - Apenas metadados não sensíveis
log.info("Autenticação realizada | user_id: a3f8c9d2 | session_id: 7e1b4a2f | ip_anon: 192.168.x.x | status: sucesso")

3. Dados que DEVEM Ser Registrados (para Segurança)

Para manter a segurança sem comprometer a privacidade, registre apenas metadados e eventos que permitam rastrear atividades suspeitas:

  • Eventos de autenticação: sucesso, falha (com contagem de tentativas), bloqueio de conta por excesso de tentativas
  • Mudanças de privilégio: promoção a administrador, revogação de permissões, alteração de grupos
  • Ações administrativas: criação/exclusão de usuários, alteração de configurações críticas
  • Operações sensíveis: transferências financeiras acima de determinado valor, exclusão de registros, exportação de dados
  • Metadados de sessão: timestamp (UTC), ID de sessão (não o token de acesso), endereço IP anonimizado (último octeto zerado), user-agent (sem versão detalhada)

Exemplo de log de auditoria seguro:

log.info({
  "evento": "alteracao_permissao",
  "timestamp": "2025-01-15T14:30:00Z",
  "user_id": "a3f8c9d2",
  "acao": "promover_para_admin",
  "target_user_id": "b7e2d1f4",
  "ip_anonimizado": "192.168.1.x",
  "session_id": "7e1b4a2f"
})

4. Técnicas de Anonimização e Mascaramento em Logs

A anonimização deve ser aplicada antes mesmo de o dado chegar ao sistema de logging. As principais técnicas incluem:

  • Mascaramento parcial: exibir apenas os últimos caracteres (ex.: ****-1234 para cartão, joao.***@email.com para e-mail)
  • Hash com salt: aplicar SHA-256 com salt único por aplicação (não use MD5 ou SHA-1)
  • Substituição por placeholder: trocar o valor real por um identificador genérico como [REDACTED] ou [FILTERED]
  • Tokenização: substituir dados sensíveis por tokens não reversíveis, mantendo o mapeamento em um cofre seguro

Exemplo de função de mascaramento em Python:

import re
import hashlib
import os

def mascarar_email(email: str) -> str:
    """Mascara e-mail mantendo apenas domínio e primeiros caracteres."""
    partes = email.split('@')
    if len(partes) != 2:
        return "[EMAIL_INVALIDO]"
    nome, dominio = partes
    if len(nome) <= 2:
        return f"{nome[0]}***@{dominio}"
    return f"{nome[:2]}***@{dominio}"

def mascarar_cpf(cpf: str) -> str:
    """Exibe apenas os três últimos dígitos do CPF."""
    cpf_limpo = re.sub(r'\D', '', cpf)
    if len(cpf_limpo) != 11:
        return "[CPF_INVALIDO]"
    return f"***.***.***-{cpf_limpo[-3:]}"

def hash_sensivel(dado: str) -> str:
    """Aplica SHA-256 com salt para dados que precisam ser comparáveis."""
    salt = os.environ.get("LOG_HASH_SALT", "salt_padrao_dev")
    return hashlib.sha256(f"{dado}{salt}".encode()).hexdigest()

# Uso seguro no log
log.info(f"Login de {mascarar_email('joao.silva@empresa.com')} | hash_cpf: {hash_sensivel('12345678901')}")

5. Estrutura e Níveis de Log Seguros

A estruturação dos logs é fundamental para permitir filtragem automática e evitar exposição acidental. Adote um schema JSON padronizado com campos obrigatórios:

Schema de log seguro (JSON):

{
  "versao": "1.0",
  "timestamp": "2025-01-15T14:30:00.123Z",
  "nivel": "INFO",
  "aplicacao": "api-pagamentos",
  "ambiente": "producao",
  "evento": "autenticacao",
  "usuario": {
    "id": "a3f8c9d2",
    "tipo": "cliente",
    "ip_anonimizado": "192.168.1.x"
  },
  "dados_evento": {
    "status": "falha",
    "motivo": "senha_incorreta",
    "tentativas_consecutivas": 3
  },
  "metadados": {
    "session_id": "7e1b4a2f",
    "correlation_id": "abc-123-def"
  }
}

Níveis de log com limites de dados:

Nível Dados permitidos Restrições
ERROR Mensagem de erro genérica, stack trace (sem dados de entrada) Nenhum PII ou credencial
WARN Eventos suspeitos, tentativas de acesso negado IP anonimizado, sem payload
INFO Eventos de negócio, auditoria Metadados apenas
DEBUG Dados detalhados para depuração Nunca em produção

6. Ferramentas e Boas Práticas de Pipeline de Logs

A gestão segura de logs vai além do código da aplicação. É necessário implementar um pipeline completo com proteções em todas as camadas:

  • Bibliotecas de logging com filtros: Use Logstash ou Fluentd com filtros customizados que removem campos sensíveis automaticamente antes do armazenamento
  • Criptografia em trânsito: Todos os logs devem trafegar via TLS 1.2+ entre aplicação, coletor e armazenamento
  • Criptografia em repouso: Logs armazenados em disco ou S3 devem usar criptografia AES-256
  • Políticas de retenção: Defina prazos máximos (ex.: 90 dias para logs de debug, 1 ano para logs de auditoria) com rotação automática
  • Monitoramento de vazamentos: Configure alertas para padrões que indicam dados sensíveis em logs (ex.: regex de CPF, e-mail, cartão de crédito)

Exemplo de filtro Logstash para remoção automática de dados sensíveis:

filter {
  mutate {
    gsub => [
      "message", "(cpf:\s*)\d{3}\.\d{3}\.\d{3}-\d{2}", "\1[REDACTED]",
      "message", "(email:\s*)[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", "\1[REDACTED]",
      "message", "(cartao:\s*)\d{4}\s?\d{4}\s?\d{4}\s?\d{4}", "\1****-****-****-****"
    ]
  }
}

7. Revisão e Teste de Logs (Prevenção Contínua)

A segurança de logs não é um esforço único — requer revisão contínua e testes automatizados:

  • Code review focado em logging: Checklist obrigatório antes de merge:
  • A mensagem de log contém dados sensíveis?
  • O nível de log é apropriado?
  • O ambiente está sendo verificado (DEBUG só em dev)?
  • Testes automatizados: Crie testes que simulam cenários de log e verificam se nenhum padrão sensível aparece na saída
  • Simulação de incidentes: Execute varreduras periódicas em logs de produção (com permissão e anonimização) para detectar vazamentos acidentais
  • Integração com SAST/DAST: Ferramentas como SonarQube, Checkmarx e Semgrep podem ser configuradas para detectar chamadas de logging que incluem variáveis potencialmente sensíveis

Exemplo de teste automatizado para detecção de dados sensíveis em logs:

import re
import pytest

def test_log_nao_contem_senha(caplog):
    """Verifica se logs de autenticação não expõem senhas."""
    from minha_app import autenticar_usuario

    autenticar_usuario("teste@email.com", "senha_secreta_123")

    for record in caplog.records:
        assert "senha_secreta_123" not in record.message
        assert re.search(r'\b\w{8,}\b', record.message) is None  # Palavras longas suspeitas

Logging seguro é uma prática que exige disciplina técnica e consciência de privacidade desde a primeira linha de código. Cada desenvolvedor tem a responsabilidade de garantir que os logs da sua aplicação ofereçam visibilidade operacional sem se tornarem uma vulnerabilidade. Implemente filtros rigorosos, use as técnicas de anonimização apresentadas e revise continuamente seus logs — sua empresa e seus usuários dependem disso.

Referências