Segurança web não se aprende apenas lendo sobre ataques

Entender que SQL Injection permite manipular consultas SQL é importante, mas não ensina, por si só, a reconhecer a falha em uma aplicação. Para aprender segurança de verdade, é necessário observar uma requisição, modificar uma entrada, interpretar a resposta e, principalmente, corrigir o problema e repetir o teste.

O laboratório não exige PHP 8.3 em todos os componentes

Os exemplos PHP seguem PHP 8.3, mas consultas preparadas e codificação de saída existem em versões anteriores. Use uma versão ainda suportada ao desenvolver a aplicação. DVWA e Juice Shop levam suas próprias dependências nos contêineres; não é necessário instalar no host a mesma linguagem de todos os laboratórios.

Confira a configuração Compose do DVWA antes de iniciar e confirme que a porta está vinculada ao loopback. Versões antigas do Docker tiveram diferenças na exposição de portas publicadas em localhost: mantenha o Engine atualizado e use também isolamento de rede no laboratório.

Documentação: DVWA · Portas Docker · OWASP.

Neste guia, você vai montar um ambiente local e praticar vulnerabilidades comuns usando aplicações criadas para treinamento. Os exercícios são direcionados exclusivamente a sistemas seus ou para os quais você tenha autorização explícita. Não execute os testes em sites de terceiros, ambientes de produção ou serviços públicos.

O conteúdo considera o OWASP Top 10:2025, que organiza riscos como controle de acesso quebrado, configuração insegura, falhas na cadeia de suprimentos, injeção e falhas de autenticação. O Top 10 é uma referência de conscientização, não uma lista completa de todas as vulnerabilidades existentes.

O que você vai precisar

  • Docker Engine e Docker Compose instalados.
  • Um navegador atualizado.
  • OWASP ZAP para interceptar e inspecionar requisições HTTP.
  • Terminal com acesso aos comandos Docker.
  • Conhecimentos básicos de HTTP, HTML, JavaScript, SQL e aplicações web.

Os laboratórios serão publicados somente na interface de loopback (127.0.0.1). Isso evita expor aplicações deliberadamente vulneráveis à rede local ou à Internet. Não altere esse vínculo para 0.0.0.0.

Preparando os laboratórios com Docker

Instalando o DVWA

O Damn Vulnerable Web Application (DVWA) é uma aplicação PHP/MariaDB propositalmente vulnerável, criada para treinamento e testes controlados. O projeto oficial recomenda não disponibilizá-la em servidores expostos à Internet.

Clone o repositório oficial e inicie os serviços:

git clone https://github.com/digininja/DVWA.git
cd DVWA
docker compose up -d

Abra http://127.0.0.1:4280. Na primeira execução, siga a tela de configuração do DVWA e use o botão de criação ou atualização do banco de dados. Entre com as credenciais padrão indicadas pela própria instalação e altere-as se o laboratório for compartilhado. No menu DVWA Security, selecione o nível Low para acompanhar os primeiros exercícios. Esse nível é intencionalmente inseguro.

Se a porta 4280 estiver ocupada, consulte o arquivo compose.yml do repositório e altere apenas a porta publicada, mantendo o endereço de escuta em 127.0.0.1.

Instalando o OWASP Juice Shop

O Juice Shop é outra aplicação intencionalmente vulnerável. Ela oferece desafios de segurança que abrangem falhas de controle de acesso, autenticação, injeção e outras categorias. É especialmente útil para observar aplicações modernas com frontend JavaScript e APIs.

docker pull bkimminich/juice-shop
docker run --rm --name juice-shop \
  -p 127.0.0.1:3000:3000 \
  bkimminich/juice-shop

Acesse http://127.0.0.1:3000. Mantenha o terminal aberto enquanto usa o laboratório. Para encerrar, pressione Ctrl+C. O parâmetro --rm remove o contêiner ao final, mas não deve ser confundido com uma garantia de remoção de todos os dados que você tenha criado em volumes externos.

Instalando o OWASP ZAP

O ZAP funciona como proxy entre o navegador e a aplicação. Ele permite visualizar requisições, respostas, cookies, cabeçalhos e parâmetros. Instale-o pelo site oficial do projeto. Configure o navegador para usar o proxy local indicado pelo ZAP, normalmente 127.0.0.1:8080, e instale o certificado de autoridade do ZAP apenas no perfil de navegador usado para o laboratório.

Comece pelo modo manual: navegue pelo DVWA ou Juice Shop e observe as requisições na aba History. Não execute varreduras automáticas contra domínios públicos. Para os exercícios deste artigo, mantenha o escopo limitado aos endereços locais.

SQL Injection: manipulando consultas ao banco de dados

SQL Injection acontece quando a aplicação incorpora dados fornecidos pelo usuário diretamente em uma instrução SQL. O banco de dados passa a interpretar parte da entrada como código SQL, em vez de tratá-la como um valor.

Como reproduzir no DVWA

  1. Entre no DVWA e abra o módulo SQL Injection.
  2. Digite o identificador simples 1 no campo e envie. Observe o registro retornado.
  3. No nível Low do laboratório, teste a entrada 1' OR '1'='1' #.
  4. Compare o resultado com a consulta normal. Se a aplicação retornar vários registros, a entrada alterou a lógica da consulta.
  5. No ZAP, abra a requisição correspondente e observe o parâmetro enviado e a resposta do servidor.

O comportamento exato depende da versão, do banco e do nível de segurança selecionado no DVWA. O payload acima é uma demonstração didática para esse módulo, não uma fórmula universal.

Como corrigir em PHP

Use consultas preparadas. Nunca concatene diretamente valores recebidos do usuário na instrução SQL.

<?php
$pdo = new PDO(
    'mysql:host=127.0.0.1;dbname=app;charset=utf8mb4',
    'app_user',
    'senha-forte',
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_EMULATE_PREPARES => false,
    ]
);

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);

if ($id === false || $id === null || $id < 1) {
    http_response_code(400);
    exit('Identificador inválido.');
}

$stmt = $pdo->prepare(
    'SELECT id, nome FROM usuarios WHERE id = :id'
);
$stmt->execute(['id' => $id]);

$usuario = $stmt->fetch(PDO::FETCH_ASSOC);

Depois de corrigir, repita o teste no laboratório. A entrada deve ser tratada como dado e não pode alterar a estrutura da consulta. Validação de tipo ajuda, mas não substitui parâmetros preparados.

Cross-Site Scripting (XSS): executando conteúdo no navegador

XSS ocorre quando dados controlados por um usuário são inseridos em uma página sem o tratamento adequado. O navegador pode interpretar esse conteúdo como HTML ou JavaScript. Há variantes refletida, armazenada e baseada no DOM.

Como reproduzir no DVWA

  1. Abra o módulo XSS (Reflected) no DVWA.
  2. Digite um nome comum e envie o formulário para observar o comportamento normal.
  3. No nível Low do laboratório, teste <script>alert('XSS')</script>.
  4. Se uma janela de alerta aparecer, o navegador interpretou a entrada como código.
  5. Repita no módulo XSS (Stored), quando disponível, usando somente uma mensagem de teste sem dados reais.

Como corrigir

Faça codificação de saída de acordo com o contexto. Para texto HTML em PHP, use htmlentities:

<?php
$comentario = is_string($_POST['comentario'] ?? null) ? $_POST['comentario'] : '';

echo htmlentities(
    $comentario,
    ENT_QUOTES | ENT_SUBSTITUTE,
    'UTF-8'
);

Não use a mesma estratégia indiscriminadamente para HTML, atributos, URLs e JavaScript: cada contexto possui regras próprias. Evite inserir dados não confiáveis em innerHTML; prefira textContent quando o objetivo for exibir texto. Uma Content Security Policy bem planejada reduz o impacto de algumas falhas, mas não substitui a codificação correta.

CSRF: induzindo uma ação com a sessão de outra pessoa

Cross-Site Request Forgery (CSRF) acontece quando um site aceita uma operação usando automaticamente a sessão autenticada do navegador, sem confirmar que a ação foi iniciada pela própria aplicação. O risco é maior em operações que alteram dados e dependem apenas de cookies enviados automaticamente.

Como estudar o problema em um laboratório

No DVWA, abra o módulo CSRF e leia o formulário e a requisição que altera a senha. Use somente uma conta descartável do laboratório. Observe no ZAP se a operação usa GET ou POST, quais parâmetros são enviados e se existe um token imprevisível vinculado à sessão. Em seguida, use a demonstração e as instruções apresentadas pelo próprio módulo para verificar se a ação é aceita sem uma confirmação válida. Não reutilize esse teste em contas reais.

Como corrigir

  • Use tokens CSRF imprevisíveis, vinculados à sessão, em operações que alteram estado.
  • Valide o token no servidor, inclusive em requisições AJAX.
  • Configure cookies de sessão com Secure, HttpOnly e uma política SameSite apropriada.
  • Não use GET para operações que modificam dados.
  • Considere validar o cabeçalho Origin ou Referer como defesa adicional, sem tratá-lo como substituto do token.

IDOR e controle de acesso quebrado

Insecure Direct Object Reference (IDOR) é uma falha de autorização: a aplicação recebe um identificador de objeto, mas não verifica se o usuário autenticado tem permissão para acessá-lo. Trocar um número na URL não deveria permitir visualizar dados de outra pessoa.

Como testar sem atacar usuários reais

  1. Use o Juice Shop e crie apenas contas descartáveis no próprio laboratório.
  2. Entre com uma conta e navegue por recursos que pertencem a ela.
  3. Abra o ZAP e identifique as requisições que consultam pedidos, cestas ou outros objetos.
  4. Observe os identificadores presentes na URL, no corpo ou na resposta.
  5. Use os desafios de controle de acesso do próprio Juice Shop para praticar a verificação. Não tente adivinhar identificadores de usuários ou serviços externos.

O sinal de vulnerabilidade é conseguir ler ou alterar um objeto que pertence a outra conta, sem autorização. O simples fato de um identificador ser numérico ou previsível não comprova, sozinho, a existência de IDOR.

Como corrigir

Verifique a autorização no servidor em toda operação. Não confie em identificadores ocultos na interface, em campos enviados pelo navegador ou em IDs difíceis de adivinhar.

<?php
$stmt = $pdo->prepare(
    'SELECT id, titulo
       FROM documentos
      WHERE id = :documento_id
        AND usuario_id = :usuario_id'
);

$stmt->execute([
    'documento_id' => $documentoId,
    'usuario_id' => $usuarioAutenticadoId,
]);

$documento = $stmt->fetch(PDO::FETCH_ASSOC);

if (!$documento) {
    http_response_code(404);
    exit('Documento não encontrado.');
}

O identificador do usuário deve vir da sessão autenticada validada no servidor, nunca de um campo livre enviado pelo cliente.

Força bruta e falhas de autenticação

Um ataque de força bruta tenta combinações de credenciais repetidamente. Reutilização de senhas, ausência de limitação de tentativas e mensagens de erro que revelam a existência de contas facilitam esse tipo de abuso.

Como observar no laboratório

  1. Use uma conta descartável do DVWA ou um desafio de autenticação do Juice Shop.
  2. Faça algumas tentativas manuais com senhas incorretas e observe o status HTTP e a mensagem retornada.
  3. Com o ZAP, compare as respostas e verifique se a aplicação limita tentativas ou aplica atraso progressivo.
  4. Se for praticar automação, mantenha a lista pequena, use somente a conta de teste e interrompa o exercício ao observar o mecanismo de bloqueio.

O objetivo é verificar a presença de controles, não descobrir a senha de uma pessoa. Não use listas de credenciais vazadas nem execute tentativas em serviços reais.

Como corrigir

  • Implemente limitação de tentativas por conta e por origem, com cuidado para não permitir negação de serviço contra uma vítima.
  • Use MFA, preferencialmente resistente a phishing quando disponível.
  • Armazene senhas com algoritmo próprio para senhas, como Argon2id, com parâmetros adequados ao servidor.
  • Use mensagens de erro genéricas e monitore padrões anormais.
  • Ofereça recuperação de conta segura e proteja também esse fluxo.

Upload inseguro de arquivos

Uma funcionalidade de upload pode permitir arquivos perigosos, conteúdo ativo, arquivos excessivamente grandes ou nomes manipulados. O risco aumenta quando o servidor armazena o arquivo em uma pasta executável ou confia apenas na extensão enviada pelo navegador.

Como testar

  1. No módulo File Upload do DVWA, use um arquivo de texto simples, por exemplo teste.txt, contendo apenas a frase arquivo de laboratório.
  2. Observe a resposta e o local de armazenamento indicado pelo laboratório.
  3. Inspecione no ZAP o nome, o tipo MIME e o corpo multipart da requisição.
  4. Verifique se a aplicação aceita extensões inesperadas ou nomes com caminhos. Não envie web shells, scripts executáveis ou arquivos maliciosos.

Como corrigir

  • Permita somente extensões necessárias e valide o tipo real do arquivo no servidor.
  • Gere um nome aleatório e não use o nome fornecido pelo cliente como caminho.
  • Defina limites de tamanho e quantidade.
  • Armazene arquivos fora da raiz pública e impeça execução no diretório de upload.
  • Quando aplicável, faça análise antimalware e reprocessamento seguro de imagens.

Path Traversal: tentando sair do diretório permitido

Path Traversal ocorre quando a aplicação monta caminhos de arquivos com dados controlados pelo usuário sem normalização e validação suficientes. Sequências como ../ podem tentar navegar para diretórios superiores.

Como estudar

No módulo File Inclusion do DVWA, observe o parâmetro usado para escolher a página. No laboratório e no nível Low, teste uma sequência de diretórios relativa ao arquivo de demonstração, como ../../../../etc/hostname, ajustando a quantidade de níveis somente dentro do contêiner local. O objetivo é observar se o conteúdo de um arquivo de teste do próprio ambiente aparece na resposta. Não tente ler arquivos de máquinas externas ou dados pessoais.

Como corrigir

A melhor abordagem é não aceitar caminhos arbitrários. Use identificadores lógicos e uma lista permitida de arquivos. Se precisar resolver caminhos, canonicalize o caminho, confirme que ele permanece dentro do diretório-base autorizado e bloqueie links simbólicos inesperados. A validação deve ocorrer no servidor.

Command Injection: quando dados viram comandos do sistema

Command Injection acontece quando uma aplicação concatena entradas em comandos do sistema operacional. Caracteres especiais podem alterar a interpretação do comando e executar operações não previstas.

Como reproduzir no DVWA

  1. Abra o módulo Command Injection do DVWA no laboratório local.
  2. Envie primeiro um endereço de loopback permitido pelo formulário, como 127.0.0.1.
  3. Compare com a entrada de laboratório 127.0.0.1; echo TESTE_LOCAL.
  4. Se a resposta incluir TESTE_LOCAL além do resultado esperado, a entrada conseguiu influenciar a interpretação do comando.

Esse teste é restrito ao contêiner de treinamento. Não substitua o comando de demonstração por comandos de exclusão, alteração de arquivos, persistência ou acesso a outros sistemas.

Como corrigir

Evite chamar o shell. Use bibliotecas e APIs específicas para a tarefa. Se um processo externo for indispensável, passe argumentos separados por uma API segura, use uma lista permitida de valores e execute com usuário de privilégios mínimos. Escapar caracteres não é uma defesa confiável quando a arquitetura permite evitar o shell.

SSRF: fazendo o servidor acessar destinos indevidos

Server-Side Request Forgery (SSRF) ocorre quando uma aplicação busca uma URL fornecida pelo usuário sem controlar adequadamente o destino. O servidor pode acabar acessando serviços internos que não deveriam estar disponíveis ao usuário.

Como testar em ambiente próprio

O DVWA e o Juice Shop não devem ser tratados como demonstrações universais de SSRF. Para estudar essa falha, crie um endpoint de laboratório separado que receba uma URL e faça uma requisição HTTP somente a um segundo serviço local descartável. Observe no log do serviço de destino que a requisição partiu do servidor da aplicação. Não use endereços de metadados de nuvem, redes privadas reais ou destinos públicos.

Como corrigir

  • Prefira uma lista permitida de hosts e esquemas, em vez de aceitar qualquer URL.
  • Bloqueie loopback, redes privadas, link-local, multicast e endereços reservados, tanto IPv4 quanto IPv6.
  • Resolva DNS e valide o endereço efetivo; revalide redirecionamentos e mudanças de resolução para reduzir DNS rebinding.
  • Desabilite redirecionamentos automáticos quando não forem necessários.
  • Aplique limites de tempo, tamanho de resposta e saída de rede no firewall ou na infraestrutura.

Uma verificação textual da URL não basta. A proteção precisa considerar o destino real da conexão e o comportamento do cliente HTTP.

DDoS e testes de carga: não confunda diagnóstico com ataque

Negação de serviço distribuída (DDoS) tenta tornar um serviço indisponível por meio de volume de tráfego ou consumo de recursos. Um teste de carga legítimo mede a capacidade de um sistema sob carga planejada, com autorização, limites e janela de execução definidos.

Teste pequeno com k6 em localhost

Instale o k6 conforme a documentação oficial. Crie um arquivo carga.js:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 1,
  duration: '10s',
};

export default function () {
  const resposta = http.get('http://127.0.0.1:3000/');
  check(resposta, {
    'status HTTP 200': (r) => r.status === 200,
  });
  sleep(1);
}

Execute apenas contra o Juice Shop local:

k6 run carga.js

Observe latência, taxa de requisições e erros. Dez segundos com um usuário virtual é um exercício de funcionamento, não um teste de capacidade ou resistência a DDoS. Não aumente a carga sem definir limites e autorização explícita.

Como reduzir o risco de indisponibilidade

Use limites de requisições, filas, timeouts, cache, proteção na borda, monitoramento e capacidade de absorção adequada. Configure limites por rota e por identidade quando possível. Uma regra única de rate limit pode prejudicar usuários legítimos ou ser contornada por distribuição de origem.

Clickjacking: escondendo uma interface dentro de outra página

Clickjacking tenta induzir a pessoa a clicar em elementos de uma aplicação legítima que foram incorporados ou sobrepostos em outra página. O usuário acredita estar interagindo com um conteúdo, mas aciona uma ação diferente.

Como observar localmente

Crie um arquivo HTML local de teste com um iframe apontando para uma página do seu próprio laboratório. Se o navegador permitir a incorporação, a página poderá aparecer dentro do iframe. Faça esse teste apenas com uma aplicação descartável e sem realizar ações sensíveis.

<!doctype html>
<html lang="pt-BR">
<meta charset="utf-8">
<title>Teste local de iframe</title>
<iframe
  src="http://127.0.0.1:3000"
  width="900"
  height="600"
  title="Aplicação de laboratório">
</iframe>
</html>

Se a página for bloqueada, inspecione os cabeçalhos da resposta para identificar a política aplicada.

Como corrigir

Configure Content-Security-Policy: frame-ancestors 'none' quando a aplicação não precisar ser incorporada. Se houver necessidade de incorporação, permita apenas origens confiáveis. O cabeçalho legado X-Frame-Options pode ser usado como compatibilidade adicional, conforme os navegadores suportados.

Configuração insegura e exposição de informações

Diretórios listáveis, páginas de diagnóstico públicas, mensagens de erro detalhadas, credenciais padrão, arquivos de backup e painéis administrativos expostos são exemplos de configuração insegura.

Como verificar no próprio projeto

  • Revise os arquivos de configuração do servidor web e do framework.
  • Confira se listagem de diretórios está desativada.
  • Verifique se arquivos .env, backups, logs e repositórios Git não estão publicados na raiz web.
  • Confirme que erros detalhados são registrados internamente, mas não exibidos ao visitante em produção.
  • Verifique se interfaces administrativas exigem autenticação e controles de acesso.

Não tente procurar arquivos sensíveis em sites de terceiros. Faça a revisão no seu próprio repositório, contêiner ou servidor de homologação.

Como organizar uma análise com OWASP ZAP

Uma análise útil não é apenas executar um scanner e copiar os alertas. Para cada funcionalidade, siga um processo reproduzível:

  1. Defina o escopo: host, aplicação, contas de teste e horários autorizados.
  2. Explore a aplicação manualmente para mapear páginas, formulários, APIs e fluxos de autenticação.
  3. Registre as requisições relevantes no ZAP e identifique parâmetros controlados pelo usuário.
  4. Teste uma hipótese por vez, começando por entradas simples e não destrutivas.
  5. Registre a evidência: requisição, resposta, comportamento observado e impacto possível.
  6. Corrija a causa no servidor, não apenas o sintoma visual.
  7. Repita exatamente o teste e confirme que a falha deixou de ocorrer.
  8. Execute testes de regressão para garantir que a correção não quebrou a funcionalidade legítima.

Scanners automatizados podem produzir falsos positivos e deixar passar falhas de lógica de negócio. Uma revisão manual continua necessária.

Checklist de proteção para sites em produção

  • Consultas SQL parametrizadas e validação de entrada no servidor.
  • Codificação de saída contextual e política CSP adequada.
  • Autorização verificada em cada operação e em cada objeto.
  • Proteção CSRF em operações autenticadas que alteram estado.
  • Senhas armazenadas com Argon2id ou algoritmo apropriado para senhas.
  • MFA e limitação de tentativas de autenticação.
  • Upload com validação real, nomes aleatórios e armazenamento fora da raiz pública.
  • Proteção contra SSRF com validação do destino e controle de saída de rede.
  • Privilégios mínimos para processos, banco de dados e contas de serviço.
  • HTTPS, cookies seguros e cabeçalhos de segurança.
  • Dependências atualizadas, inventariadas e obtidas de fontes confiáveis.
  • Logs úteis, alertas, backups testados e plano de resposta a incidentes.
  • Testes de segurança repetidos após mudanças importantes.

Encerrando os laboratórios

Ao terminar, pare os contêineres. No diretório do DVWA, execute:

docker compose down

Se você não precisa preservar os dados do laboratório e deseja removê-los, revise os volumes antes de executar comandos de remoção. No Juice Shop, pressione Ctrl+C no terminal em que ele está rodando.

Pratique: Aprender a documentar uma falha e provar a correção.

Use este roteiro para transformar a leitura em uma verificação concreta.

  1. Escolha um exercício em DVWA ou Juice Shop local e registre o fluxo normal antes de modificar qualquer entrada. Use somente contas e dados fictícios.
  2. Descreva a condição que permite a falha, o efeito observado e a fronteira de confiança violada. Diferencie um erro de validação de uma falha de autorização.
  3. Implemente a correção em um projeto de laboratório e repita o teste de abuso e os testes de uso legítimo. Acrescente um caso de regressão que falhe se a vulnerabilidade voltar.

Como conferir o resultado

Um relatório útil mostra o pré-requisito, a evidência, o impacto e como verificar a solução. A ausência de uma mensagem de erro não prova segurança. Mantenha o laboratório isolado e não reproduza os exemplos em serviços de terceiros.

Continue o estudo: SQL Injection em PHP: identificar e prevenir com PDO · Segurança no Linux: SSH, firewall, aplicações e backups.

Conclusão

Aprender segurança web exige mais do que decorar nomes de ataques. O processo correto é montar um ambiente controlado, reproduzir uma falha, entender por que ela acontece, implementar a correção e repetir o teste. DVWA e OWASP Juice Shop oferecem aplicações deliberadamente vulneráveis para esse aprendizado; OWASP ZAP ajuda a observar o tráfego e documentar os resultados.

Em aplicações reais, priorize correções estruturais: consultas preparadas, autorização no servidor, codificação contextual, autenticação forte, validação de uploads e restrições de rede. Segurança não é uma etapa isolada antes da publicação, mas parte do ciclo de desenvolvimento e manutenção.

Referências oficiais