Práticas de Codificação Segura (Secure Coding Practices)
Segurança não pode ser aparafusada em uma aplicação depois de construída. Deve ser projetada na arquitetura e escrita no código desde a primeira linha. O custo de corrigir uma vulnerabilidade em produção é 6-15x maior do que corrigi-la durante o desenvolvimento.
Nunca confie em dados do usuário, do cliente ou de qualquer sistema externo.
Sempre prefira allow-listing a block-listing. Listas de bloqueio são inerentemente incompletas, atacantes constantemente inventam novos truques de codificação e técnicas de ofuscação para evadi-las.
Validação Server-Side vs. Client-Side
- Validação client-side (JavaScript no navegador) melhora UX. Não é um controle de segurança. Atacantes a ignoram trivialmente usando DevTools, Burp Suite ou curl.
- Validação server-side é obrigatória. Cada input deve ser validado no servidor.
2. Codificação de Saída (Output Encoding)
A defesa primária contra XSS (Cross-Site Scripting, ou Script entre Sites). Antes de renderizar dados do usuário no navegador, codifique-os para o contexto de saída apropriado.
Regra de ouro: se você usa dangerouslySetInnerHTML (React), [innerHTML] (Angular) ou v-html (Vue), deve sanitizar o input primeiro usando uma biblioteca como DOMPurify. Essas saídas de emergência desabilitam a proteção XSS do framework.
3. Consultas Parametrizadas (Parameterized Queries)
A única defesa confiável contra SQL Injection (Injeção SQL) é separar código SQL dos dados do usuário.
O driver do banco trata valores parametrizados estritamente como dados, nunca como código SQL executável.
4. Menor Privilégio (Least Privilege)
Cada usuário, processo e aplicação deve ter apenas as permissões mínimas necessárias.
Exemplos no Nível de Aplicação
- O usuário do banco de dados da aplicação web deve ter
SELECT, INSERT, UPDATE em tabelas específicas: não DROP TABLE ou GRANT ALL.
- Um microserviço que apenas lê dados deve ter credenciais somente leitura.
- Um pipeline CI/CD fazendo deploy em staging não deve ter credenciais de produção.
O Princípio do Raio de Explosão (Blast Radius)
Menor privilégio limita o raio de explosão de um comprometimento. Se um atacante compromete um serviço com permissões mínimas, o dano é contido.
5. Gerenciamento de Segredos (Secrets Management)
Nunca hardcode segredos (chaves de API, senhas de banco, chaves de criptografia, tokens) no código-fonte.
Segundo o relatório da GitGuardian de 2023, mais de 10 milhões de novos segredos foram detectados em commits públicos do GitHub em um único ano.
Onde Segredos Devem Ficar
Hooks de Pré-commit (Pre-commit Hooks)
Use ferramentas como gitleaks, trufflehog ou detect-secrets como hooks de pré-commit para escanear segredos antes de serem commitados:
6. Segurança de Dependências (Dependency Security)
Aplicações modernas dependem de centenas de pacotes open-source. Cada dependência faz parte da sua superfície de ataque.
Risco na Cadeia de Suprimentos (Supply Chain Risk)
- Log4Shell (2021): Vulnerabilidade crítica no Apache Log4j permitia execução remota de código com uma única mensagem de log. CVSS: 10.0/10.0.
- event-stream (2018): Pacote npm popular foi comprometido por um novo mantenedor que injetou código direcionado a carteiras de criptomoeda.
Ferramentas de Escaneamento
Quando uma aplicação encontra um erro, deve falhar de forma que não conceda acesso adicional ou vaze informações.
8. Modelagem de Ameaças: STRIDE (Threat Modeling)
O framework STRIDE categoriza ameaças:
Principais Conclusões
- Valide todo input server-side: Allow-lists sobre block-lists.
- Codifique toda saída: Codificação contextual previne XSS.
- Parametrize todas as consultas: A única defesa confiável contra SQLi.
- Nunca hardcode segredos: Use gerenciadores de segredos e hooks de pré-commit.
- Escaneie dependências continuamente: Automatize no CI/CD.
- Falhe com segurança: Erros genéricos para usuários, logs detalhados server-side.
- Modele ameaças cedo: STRIDE durante o design, não após o deploy.