OWASP Top 10 explicado para desenvolvedores: as 10 falhas que mais derrubam aplicações
Um guia da taxonomia OWASP Top 10 para quem escreve código: a causa real de cada classe de risco e a defesa que fecha o buraco na prática.
Neste artigo
Um endpoint que devolve o pedido GET /pedidos/1043 funciona lindamente na demonstração. O usuário logado vê o próprio pedido, o gráfico de vendas atualiza, o QA aprova. Meses depois, alguém troca o número na barra de endereço para 1042 e enxerga a fatura de outra pessoa — nome, endereço, últimos quatro dígitos do cartão. Nenhuma linha daquele código estava "com bug" no sentido tradicional: ele fazia exatamente o que foi escrito. O problema é que ninguém escreveu a parte que verifica se aquele usuário tem direito de ver aquele pedido. Esse é o tipo de falha que o OWASP Top 10 existe para nomear, classificar e ajudar você a antecipar antes que vire manchete.
O OWASP Top 10 é a lista de referência mais conhecida sobre riscos de segurança em aplicações web, publicada pela Open Worldwide Application Security Project. A edição atual amplamente usada é a de 2021, e ela não é uma lista de vulnerabilidades isoladas — é uma taxonomia de classes de risco, agrupadas por padrão de causa e por prevalência real medida em dados de milhares de aplicações. Entender essa distinção é o primeiro passo: você não decora dez bugs, você aprende dez formas recorrentes de errar para reconhecê-las no seu próprio código.
O que o Top 10 é — e o que ele não é#
O Top 10 não é um checklist de conformidade que, cumprido, garante uma aplicação segura. Ele cobre os riscos mais críticos e mais comuns, mas uma aplicação pode passar por todos os dez itens e ainda cair por uma falha específica do seu domínio. Tratá-lo como "se marquei tudo, estou seguro" é justamente o erro que ele tenta combater. O Top 10 é uma ferramenta de conscientização e de linguagem comum: quando um revisor comenta "isso é um A01" num pull request, todo o time entende que se trata de uma falha de controle de acesso, sem precisar reescrever o cenário inteiro.
Também vale entender que a lista muda de edição para edição, e as mudanças contam uma história. Categorias sobem, descem, se fundem e às vezes nascem de análise da comunidade em vez de puro dado estatístico. A ordem reflete uma combinação de frequência, severidade e explorabilidade. Não leia a posição como "o item 1 é sempre mais perigoso que o item 10 no seu caso" — leia como "estatisticamente, é aqui que a maioria erra primeiro".
A01 — Broken Access Control#
Controle de acesso quebrado é a categoria número um, e não por acaso: é o cenário da fatura vazada que abriu este texto. A falha acontece quando a aplicação não verifica, no servidor, se o usuário autenticado tem permissão para executar aquela ação sobre aquele recurso. Inclui o IDOR clássico (trocar um identificador na URL), a escalada de privilégio (um usuário comum chamando um endpoint administrativo), o acesso entre inquilinos num sistema multi-tenant, e a confiança indevida em campos vindos do cliente.
A defesa é conceitualmente simples e operacionalmente disciplinada: autorização é decidida no servidor, sempre, com base na identidade verificada do token — nunca no id que o cliente mandou. Verificar if (user.isAdmin) no front-end é experiência de usuário, não controle. A rota, a função e a query precisam re-perguntar "esse sujeito pode tocar neste objeto?" a cada requisição. Negar por padrão, permitir por exceção explícita.
A02 — Cryptographic Failures#
Antes chamada de "exposição de dados sensíveis", esta categoria trata do que acontece com dados que exigem proteção — senhas, tokens, dados pessoais, informação financeira — quando a criptografia está ausente, mal aplicada ou obsoleta. Guardar senha em texto puro é o exemplo caricato, mas a realidade é mais sutil: usar um hash rápido como MD5 ou SHA-256 para senha (quando o correto é uma função de derivação lenta como argon2id ou bcrypt), transmitir dados sem TLS, reutilizar vetores de inicialização, ou confiar em algoritmos quebrados.
O princípio de defesa é conhecer a diferença entre criptografia (reversível, para confidencialidade em trânsito e repouso) e hashing (unidirecional, para verificar sem armazenar o original), classificar quais dados precisam de qual proteção, e usar primitivas modernas com bibliotecas revisadas em vez de inventar esquema próprio.
A03 — Injection#
Injeção — de SQL, de comando de sistema operacional, de LDAP — permanece no topo há mais de duas décadas porque a causa é estrutural: dados controlados pelo atacante chegam a um interpretador que não distingue código de dado. Uma query montada por concatenação de string trata a entrada do usuário como parte do comando, e um ' OR '1'='1 transforma um filtro em um portão aberto. A defesa canônica é a separação entre plano de execução e dado: consultas parametrizadas (prepared statements) fazem o banco receber a estrutura da query e os valores por canais distintos, encerrando a classe. Onde parametrizar não é possível (nome de coluna em ORDER BY), vale allowlist estrita.
A04 — Insecure Design#
Esta categoria, introduzida em 2021, separa falha de projeto de falha de implementação, e é uma das mais importantes de internalizar. Um código pode estar impecavelmente implementado — sem bug, bem testado — e ainda ser inseguro porque o desenho não previu um abuso. Um fluxo de recuperação de senha que envia um código de seis dígitos sem limite de tentativas está corretamente implementado e fundamentalmente inseguro. A defesa mora antes do teclado: threat modeling, casos de abuso ao lado dos casos de uso, e padrões de projeto seguros escolhidos deliberadamente. Nenhuma quantidade de testes de implementação conserta um design que abriu a porta de propósito.
A05 — Security Misconfiguration#
Configuração insegura é a categoria dos defaults perigosos, dos serviços expostos que deveriam estar fechados, das mensagens de erro verbosas que vazam stack trace e versão de banco, dos cabeçalhos de segurança ausentes, das contas e senhas padrão que nunca foram trocadas, dos buckets de armazenamento públicos por engano. É onipresente porque a superfície de configuração de uma aplicação moderna é gigantesca: framework, servidor, container, orquestrador, provedor de nuvem. A defesa é ter um baseline endurecido, aplicado de forma reprodutível (infraestrutura como código), com o mínimo de recursos habilitados e erros que não contam ao atacante mais do que ele precisa saber.
A06 — Vulnerable and Outdated Components#
Você não escreve a maior parte do código que roda em produção — suas dependências escrevem. Uma vulnerabilidade conhecida numa biblioteca transitiva que você nem sabia que estava no grafo é um vetor de ataque tão real quanto um bug no seu próprio código. A defesa é inventário (saber o que você usa, idealmente via SBOM), varredura contínua de dependências contra bases de vulnerabilidade, e um processo de atualização que não deixa componentes apodrecerem por anos. "Se está funcionando, não mexe" é uma filosofia que envelhece mal em segurança.
A07 — Identification and Authentication Failures#
Falhas de identificação e autenticação cobrem tudo que permite um atacante se passar por outro usuário: senhas fracas aceitas, ausência de proteção contra força bruta, sessões que não expiram, tokens previsíveis, MFA ausente onde deveria existir, e fluxos de reset que podem ser abusados. A defesa combina hashing forte de credenciais, políticas de senha baseadas em comprimento e verificação contra listas vazadas, segundo fator (idealmente resistente a phishing, como passkeys), geração de tokens por CSPRNG e gestão de sessão correta em cookies HttpOnly.
A08 — Software and Data Integrity Failures#
Esta categoria trata de confiar em código ou dados sem verificar sua integridade: um pipeline de CI/CD que puxa artefatos sem checar assinatura, uma atualização automática sem verificação, desserialização de dados não confiáveis que permite execução de código. O comprometimento da cadeia de suprimentos de software — quando o atacante injeta código malicioso no build em vez de na aplicação em produção — vive aqui. A defesa é verificar assinaturas, controlar a origem dos artefatos, e nunca desserializar dado não confiável em objetos que disparam comportamento.
A09 — Security Logging and Monitoring Failures#
Um ataque que ninguém detecta é um ataque bem-sucedido por definição. Esta categoria não é sobre a falha que deixou o atacante entrar, mas sobre a cegueira que o deixou operar por semanas sem alarme. Logins falhados que não são registrados, ausência de alertas, logs sem trace_id que impossibilitam reconstruir o que aconteceu — tudo isso transforma um incidente contornável em uma catástrofe descoberta tarde. A defesa é logar eventos de segurança relevantes com contexto suficiente para investigação, monitorar em tempo real e ter alertas que efetivamente chegam a alguém.
A10 — Server-Side Request Forgery (SSRF)#
SSRF fecha a lista: acontece quando a aplicação busca um recurso remoto a partir de uma URL fornecida pelo usuário sem validar o destino, permitindo ao atacante forçar o servidor a fazer requisições para onde ele não deveria — serviços internos, o endpoint de metadados da nuvem, portas que só o servidor alcança. A defesa é allowlist de destinos, bloqueio de faixas de IP internas, e desconfiança de qualquer URL que o cliente controle.
Como um desenvolvedor usa isso no dia a dia#
A maior utilidade do Top 10 não é numa auditoria anual — é no fluxo cotidiano. Em code review, ele vira uma lista mental de perguntas: essa rota verifica autorização no servidor (A01)? Essa query está parametrizada (A03)? Esse dado sensível está protegido corretamente (A02)? Essa configuração vaza informação (A05)? Na definição de pronto de uma feature, cabe exigir que as classes relevantes tenham sido consideradas. No design de algo novo, um threat modeling leve percorre as categorias e pergunta "quais dessas se aplicam aqui?".
O Top 10 não substitui um SDLC seguro, testes de segurança automatizados no CI, ou um pentest antes de lançar algo crítico — ele é a espinha dorsal conceitual que dá nome ao que essas práticas procuram. Um time que fala essa língua comum comete menos os mesmos erros básicos, e comete-os de forma mais rara, porque reconhece a classe antes de escrever a linha. Segurança não é um recurso que se adiciona no fim; é um conjunto de reflexos que se treina, e o Top 10 é o alfabeto desses reflexos.
