Skip to main content

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.

1. Validação de Entrada (Input Validation)

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

7. Falhar com Segurança (Fail Securely)

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

  1. Valide todo input server-side: Allow-lists sobre block-lists.
  2. Codifique toda saída: Codificação contextual previne XSS.
  3. Parametrize todas as consultas: A única defesa confiável contra SQLi.
  4. Nunca hardcode segredos: Use gerenciadores de segredos e hooks de pré-commit.
  5. Escaneie dependências continuamente: Automatize no CI/CD.
  6. Falhe com segurança: Erros genéricos para usuários, logs detalhados server-side.
  7. Modele ameaças cedo: STRIDE durante o design, não após o deploy.