Web Cache Deception (WCD) é uma técnica onde o atacante engana um cache intermediário (CDN, reverse proxy) para armazenar uma resposta que contém dados sensíveis de outro usuário.
A vulnerabilidade existe quando:
- O cache decide cachear baseado na extensão da URL (.css, .js, .png, etc.)
- O backend ignora o sufixo e resolve a rota normalmente (/account → dados do usuário)
- O backend não envia headers Cache-Control adequados (ou o cache os ignora)
| Cache Deception | Cache Poisoning | |
|---|---|---|
| Quem acessa a URL maliciosa? | A vítima | O atacante |
| O que é cacheado? | Resposta legítima com dados da vítima | Resposta manipulada pelo atacante |
| Vetor | Induzir vítima a clicar em link | Manipular headers/params que entram na cache key |
| Resultado | Atacante lê dados privados do cache | Todos os usuários recebem conteúdo malicioso |
Vítima (autenticada) ──→ GET /account/x.css ──→ Nginx (cache)
│
"extensão .css → cachear!"
│
▼
Flask (backend)
resolve /account
retorna dados sensíveis
│
▼
Nginx armazena no cache
key: /account/x.css
Atacante (não autenticado) ──→ GET /account/x.css ──→ Nginx
│
cache HIT → retorna
dados da vítima
- Cache intermediário que decide cachear por extensão de URL
- Backend que ignora path segments extras (path normalization)
- Ausência de
Cache-Control: no-store, privatenas respostas sensíveis - Vítima precisa acessar a URL crafted (requer interação: phishing, img tag, etc.)
/account/x.css → extensão estática
/account%2fx.css → URL encoding
/account/..%2fstatic/x.css → path traversal normalizado
/account;x.css → path parameter (Tomcat/Java)
/account%00.css → null byte (legacy)
/account/.css → dot segment
# Instalar dependências
sudo apt install nginx
pip3 install flask
# Iniciar
./setup.sh start
# Em outro terminal, executar exploit
python3 exploit.py --target http://localhost:8080
# Parar
./setup.sh stopdocker-compose up -d
python3 exploit.py --target http://localhost:8080
docker-compose down- Backend: Sempre enviar
Cache-Control: no-store, privateem respostas autenticadas - Cache/Proxy: Não cachear baseado apenas em extensão. Respeitar headers do backend
- Cache/Proxy: Configurar
proxy_cache_bypasspara requests com Cookie - WAF: Bloquear URLs com extensões estáticas em paths de aplicação
location ~* \.(css|js|png|jpg)$ {
# Não cachear se tem cookie de sessão
proxy_cache_bypass $http_cookie;
proxy_no_cache $http_cookie;
# ... resto da config
}@app.after_request
def add_cache_headers(response):
if "user" in session:
response.headers["Cache-Control"] = "no-store, private"
return response