Server-Side Request Forgery (SSRF)

1. O que é SSRF e por que importa para Devs

1.1. Definição

Server-Side Request Forgery (SSRF) é uma vulnerabilidade onde um servidor web faz requisições não intencionais para recursos internos ou externos com base em entrada fornecida pelo usuário. O ataque explora a confiança que o servidor tem em si mesmo para acessar sistemas que normalmente seriam inacessíveis ao atacante.

1.2. Impactos

  • Acesso a redes internas e serviços privados
  • Leitura de metadados de instâncias cloud (AWS, GCP, Azure)
  • Bypass de firewalls e controles de acesso
  • Execução de comandos em serviços internos (Redis, Memcached)
  • Exfiltração de dados sensíveis

1.3. SSRF básico vs. cego (blind SSRF)

No SSRF básico, o atacante recebe resposta direta do servidor alvo (ex: conteúdo de um arquivo interno). No blind SSRF, o atacante não vê a resposta, mas pode inferir sucesso por meio de side-channels como tempo de resposta, logs ou callbacks externos.

2. Como SSRF funciona na prática

2.1. Fluxo típico de ataque

Usuário → Envia URL maliciosa → Servidor processa → Servidor faz requisição interna → Dado vaza

2.2. Exemplos de funcionalidades vulneráveis

  • Webhooks: servidor envia POST para URL fornecida pelo usuário
  • Importadores de URL: ferramentas que baixam conteúdo de URLs
  • Proxies: servidores que buscam recursos em nome do cliente
  • Validadores de URL: serviços que verificam se um link está ativo

2.3. Cenário real: ataque a metadados AWS

# Exemplo de URL maliciosa para acessar metadados AWS
http://169.254.169.254/latest/meta-data/

# O servidor vulnerável faz GET para essa URL e retorna dados sensíveis
# Como chaves de acesso, ID da instância, etc.

3. Técnicas de exploração comuns

3.1. Bypass de validação de URL

# Redirecionamento
http://legitimo.com/redirect?url=http://169.254.169.254/

# Encoding de IP
http://0x7f000001/  # 127.0.0.1 em hex
http://2130706433/    # 127.0.0.1 em decimal

# Variações de DNS
http://localhost/
http://127.1/
http://0/

3.2. Uso de protocolos alternativos

# Protocolo file:// para ler arquivos locais
file:///etc/passwd

# Protocolo gopher:// para interagir com serviços TCP
gopher://redis:6379/_SET%20key%20value

# Protocolo dict:// para consultar serviços
dict://localhost:6379/info

3.3. Exploração de serviços internos

# Redis - injeção de comandos
gopher://localhost:6379/_SET%20mykey%20"malicious"%0D%0A

# Memcached - armazenamento de payload
http://localhost:11211/set%20key%200%200%205%0D%0Ahello

# Bancos de dados - consulta via HTTP
http://db.internal:5432/

4. Estratégias de prevenção: validação e sanitização

4.1. Whitelist de domínios e IPs permitidos (nunca blacklist)

# Exemplo de whitelist em Python
ALLOWED_DOMAINS = ["api.trusted.com", "cdn.trusted.com"]
ALLOWED_IPS = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]

def is_allowed(url):
    parsed = urlparse(url)
    hostname = parsed.hostname
    ip = socket.gethostbyname(hostname)

    if hostname not in ALLOWED_DOMAINS:
        return False
    if not is_private_ip(ip):
        return False
    return True

4.2. Validação rigorosa de esquemas (apenas https://) e parsing de URL

# Validação de esquema em Node.js
function validateURL(url) {
    const parsed = new URL(url);
    if (parsed.protocol !== 'https:') {
        throw new Error('Apenas HTTPS permitido');
    }
    if (parsed.hostname.includes('.')) {
        // Verifica se é um domínio válido
    }
    return parsed;
}

4.3. Bloqueio de resolução de DNS para IPs privados

# Exemplo em Python com verificação de IP privado
import ipaddress

def is_private_ip(ip_string):
    ip = ipaddress.ip_address(ip_string)
    return ip.is_private or ip.is_loopback or ip.is_link_local

def safe_request(url):
    parsed = urlparse(url)
    ip = socket.gethostbyname(parsed.hostname)
    if is_private_ip(ip):
        raise Exception("Acesso a IP privado bloqueado")
    return requests.get(url, timeout=5)

5. Defesas no nível de rede e infraestrutura

5.1. Isolamento de rede: VPC, sub-redes privadas, grupos de segurança

  • Servidores de aplicação em sub-redes privadas
  • Acesso a banco de dados apenas via IPs internos
  • Grupos de segurança que bloqueiam tráfego de saída não autorizado

5.2. Firewall de saída (egress filtering) e proxies reversos

# Regras de firewall de saída (exemplo iptables)
-A OUTPUT -d 10.0.0.0/8 -j DROP
-A OUTPUT -d 172.16.0.0/12 -j DROP
-A OUTPUT -d 192.168.0.0/16 -j DROP
-A OUTPUT -d 169.254.169.254 -j DROP
-A OUTPUT -p tcp --dport 6379 -j DROP  # Redis

5.3. Uso de serviços de metadados protegidos (IMDSv2 no AWS)

# IMDSv2 requer token de sessão
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/

6. Boas práticas de codificação para evitar SSRF

6.1. Nunca confiar em URLs fornecidas pelo usuário para requisições diretas

# ERRADO - direto da entrada do usuário
url = request.GET.get('url')
response = requests.get(url)

# CORRETO - usar whitelist e validação
url = request.GET.get('url')
if not is_allowed(url):
    return error_response()
response = safe_request(url)

6.2. Implementar timeouts e limites de redirecionamento

# Timeout e limite de redirecionamentos em Python
response = requests.get(
    url,
    timeout=5,           # Timeout total
    allow_redirects=True,
    max_redirects=5      # Máximo de redirecionamentos
)

6.3. Desabilitar redirecionamentos automáticos e protocolos perigosos

# Desabilitar redirecionamentos em Node.js com axios
const response = await axios.get(url, {
    maxRedirects: 0,
    timeout: 5000,
    validateStatus: function (status) {
        return status >= 200 && status < 300;
    }
});

7. Testes e detecção de SSRF

7.1. Ferramentas de teste

  • Burp Suite: plugin Collaborator para detectar blind SSRF
  • SSRFmap: ferramenta automatizada para exploração
  • Interactsh: servidor de callback para detectar requisições externas
# Exemplo de teste manual com curl
curl -v "http://vulnerable.com/fetch?url=http://169.254.169.254/latest/meta-data/"

# Teste com callback externo
curl "http://vulnerable.com/fetch?url=http://YOUR_INTERACTSH.oastify.com/test"

7.2. Monitoramento de logs: requisições inesperadas para IPs internos

# Logs a monitorar (exemplo de padrão)
GET /latest/meta-data/  # Tentativa de SSRF em cloud
Connection to 127.0.0.1:6379  # Conexão inesperada com Redis
DNS query for internal.trusted.com  # Resolução de DNS suspeita

7.3. Checklist de revisão de código para identificar pontos cegos

  • [ ] Todas as URLs de entrada passam por whitelist?
  • [ ] Esquemas são validados (apenas HTTPS)?
  • [ ] Redirecionamentos são limitados?
  • [ ] Timeouts estão configurados?
  • [ ] IPs privados são bloqueados?
  • [ ] Protocolos perigosos (file://, gopher://) estão desabilitados?
  • [ ] Metadados cloud estão protegidos (IMDSv2)?
  • [ ] Firewall de saída está configurado?

8. Conclusão

SSRF continua sendo uma das vulnerabilidades mais perigosas em aplicações modernas, especialmente em ambientes cloud. A prevenção eficaz exige uma abordagem em camadas: validação rigorosa de entrada, isolamento de rede, configuração segura de infraestrutura e monitoramento constante. Como desenvolvedor, sua responsabilidade é garantir que o servidor nunca faça requisições não autorizadas — mesmo que indiretamente. Lembre-se: a confiança no servidor é a principal arma do atacante.

Referências