O site antigo dizia "criptografia AES-256, a mesma do Google Cloud". Isso não quer dizer nada. Segue o que quer dizer.
Borda
TLS e cabeçalhos de segurança
Certificado Let’s Encrypt renovado sozinho pelo Traefik e HTTP redirecionado para HTTPS. Política de conteúdo restritiva, negação de enquadramento, nosniff e política de referência, reaplicadas em cada bloco de configuração, porque cabeçalho de nginx não é herdado.
Dados
Criptografia em repouso
CPF cifrado dentro do banco. Token de acesso de terceiro guardado com envelope encryption: uma chave cifra a chave que cifra o dado, então cópia do banco não vira acesso à conta do cliente.
Autenticação
Sessão
Cookie assinado com HMAC-SHA256, comparado em tempo constante, httpOnly e restrito ao próprio site. O segredo é obrigatório em produção: sem ele a aplicação se recusa a subir, sem cair num valor de desenvolvimento. E o token carrega a impressão digital da credencial, trocar a senha derruba na hora toda sessão antiga, em qualquer aparelho, sem tabela de sessão no banco.
Autorização
Controle de acesso em três camadas
Guarda no middleware, revalidação do usuário a cada requisição e verificação dentro de cada ação de servidor. Usuário removido, bloqueado ou com credencial trocada cai no logout na requisição seguinte, não no próximo login.
Força bruta
Limite de tentativas de login
Login e recuperação de senha limitados por e-mail e por IP, com uma mensagem de erro única que não revela se o endereço existe. Link de redefinição de uso único, válido por 30 minutos e invalidado se a senha mudar.
Disponibilidade
Limite de tráfego na borda
Contamos os arquivos que a home pede, consideramos o visitante de celular atrás do NAT da operadora e escolhemos números que barraram um teste de carga de 654 requisições por segundo sem barrar o tráfego legítimo simulado no mesmo teste. O serviço público de captação aceita 10 requisições por minuto por IP.
Infraestrutura
O servidor
Firewall ufw fechado e fail2ban no SSH, instalado depois de contarmos 346 tentativas de força bruta em 7 dias no log. Container multi-stage rodando com usuário não-root. Serviço de e-mail em rede interna, sem porta exposta no host.
Segredos
Segredos fora do bundle
Nenhum segredo no pacote que vai para o navegador. Variável de ambiente no servidor e webhook do Stripe validado por assinatura. No sistema distribuído como instalador, o segredo de sessão é gerado no primeiro boot na máquina do cliente, com permissão restrita, o executável não sai daqui com segredo dentro.
Validação
Entrada não confiável
Schema validado na borda da aplicação. Preço e frete recalculados no servidor, porque o valor que vem do navegador não é dado, é sugestão. Upload restrito ao administrador, com lista de tipos permitidos, limite de tamanho e nome de arquivo aleatório.
Rastro
Auditoria e backup
Cada acesso grava data, responsável e dispositivo, e conflito resolvido na sincronização offline fica registrado. O backup do banco sai da máquina que o gerou; frequência e retenção são acordadas no projeto, e a restauração é testada, backup que nunca foi restaurado é só um arquivo.
Cadeia de suprimento
Dependências
Versões travadas em lockfile, atualização revisada antes de subir e superfície pequena de propósito: uma das landings entregues tem zero biblioteca JavaScript de terceiros, só a fonte tipográfica.
Processo
Checklist replicável
Mantemos um SECURITY.md de 24 KB que vai de projeto em projeto, com o que foi verificado, o que ficou de fora e por quê. Você pode pedir para ler o do seu projeto.