Host header injection: como funciona, como detectar e como corrigir
A aplicação confia no Host ou no X-Forwarded-Host enviado pelo cliente ao montar links, abrindo espaço para envenenar reset de senha e cache.
Severidade típica: Alta · Verificado pelo módulo da NovaPentest: Host Header Injection
O que é
Host header injection é o nome dado a vulnerabilidades em que a aplicação trata o header Host, ou um header de encaminhamento que faz o papel dele, como confiável ao montar links, redirects ou decisões de roteamento. Os dois valores vêm do cliente e podem ser qualquer coisa.
No HTTP/1.1, o header Host diz ao servidor para qual site é a requisição, o que permite que um único IP sirva vários sites. Quando a requisição passa por um reverse proxy ou load balancer, o host original costuma seguir em headers como X-Forwarded-Host, X-Host ou X-Forwarded-Server. Muitos frameworks descobrem "o host atual" a partir desses headers automaticamente, para que as URLs geradas batam com o domínio público.
O problema aparece quando esse valor chega a algo que importa: o link de reset de senha num e-mail, uma URL absoluta no header Location, a URL de um script ou link canônico na página, uma entrada de cache ou a escolha de um virtual host interno. Se a aplicação aceita qualquer valor, em vez de conferir com os domínios que realmente atende, o atacante passa a controlar parte dessa saída.
Servidores web costumam mandar um Host desconhecido para o virtual host padrão, que pode ser a própria aplicação, então o servidor web sozinho não evita o problema. Headers de encaminhamento são um ponto cego frequente: só deveriam ser definidos pelos seus proxies, mas, se a aplicação não estiver configurada para saber em quais proxies confiar, ela não distingue um header definido pelo proxy de um enviado pelo cliente.
O OWASP Web Security Testing Guide trata essa classe em "Testing for Host Header Injection".
Como é explorada
A forma de exploração depende de onde o host injetado vai parar.
1. Envenenamento do reset de senha. É o caso de alto impacto mais comum. O atacante pede um reset de senha para o e-mail da vítima enviando um Host ou X-Forwarded-Host forjado, apontando para um domínio dele. A aplicação monta o link de reset com esse valor e manda por e-mail para a vítima. Se ela clicar, o token de reset vai para o servidor do atacante, que o usa no site real para tomar a conta. O e-mail vem de fato do serviço legítimo, o que deixa o link com cara de confiável.
2. Web cache poisoning. Se o cache não inclui o header de encaminhamento na chave, uma única requisição com host forjado pode guardar uma resposta com links ou URLs de script controlados pelo atacante e entregá-la a todos os visitantes.
3. Redirects via Location. Um redirect absoluto montado a partir do header aponta para fora do site quando o valor é forjado. O navegador não envia um header forjado em nome da vítima, então isso costuma importar em combinação com cache.
4. Virtual hosts internos e roteamento. Colocar no Host o nome de algo interno, como um virtual host de administração, pode dar acesso a aplicações que deveriam ser só internas, ou pular regras de acesso baseadas no host.
5. Manipulação de requisições do lado do servidor, quando o valor do host é usado para montar chamadas a serviços de back-end.
Uma reflexão que fica só na resposta do próprio atacante é inofensiva, já que o navegador da vítima não manda o header forjado. O impacto vem das reflexões que persistem ou chegam a outra pessoa: e-mails, cache e roteamento no servidor. Por isso vale testar o fluxo de reset de verdade.
Como detectar
A verificação de host header do NovaPentest envia requisições GET para a URL do alvo, sem seguir redirects, com um host forjado em um header de encaminhamento por vez: X-Forwarded-Host, depois X-Host, depois X-Forwarded-Server. O header Host real não é alterado. O valor forjado é um domínio de teste do próprio scanner, não do alvo.
Se o domínio forjado aparecer no corpo da resposta ou no header Location, ele registra "Host header injection" com severidade High, informando o header e se a reflexão foi no Location ou no corpo, mapeado para CWE-644 e OWASP A01:2021. Ele para no primeiro header que refletir.
Limites importantes: a verificação não envia um header Host modificado, não testa variações com URI absoluta ou Host duplicado e não aciona reset de senha nem outros fluxos de e-mail. Ela confirma que a aplicação confia num header de encaminhamento na resposta que gera, não que um ataque específico, como o envenenamento do reset, funcione. Só a URL configurada do alvo é testada, e outros endpoints, inclusive páginas de reset, podem se comportar de outro jeito. A URL do alvo é remontada a partir de esquema, host e path, então uma porta fora do padrão não é mantida. X-Forwarded-Host e X-Host também são testados na verificação de cache poisoning, então a mesma causa pode gerar os dois achados.
Para verificar manualmente:
1. Reproduza a reflexão: curl -s -D - -H "X-Forwarded-Host: test.invalid" https://example.com/ | grep -i test.invalid, que procura tanto nos headers quanto no corpo.
2. Teste o próprio header Host: curl -s -D - -H "Host: test.invalid" https://example.com/ e veja se você recebe a aplicação ou um erro.
3. Com uma conta de teste, peça um reset de senha enviando o header forjado e confira o link no e-mail que chegar.
Como corrigir
1. Nunca monte URLs sensíveis a partir de headers da requisição. Links de reset de senha, de verificação de e-mail, redirect URIs de OAuth e redirects absolutos devem usar uma URL base pública vinda da configuração, como https://app.example.com. Essa mudança sozinha acaba com o envenenamento do reset, independentemente dos headers recebidos, então faça isso primeiro.
2. Valide o Host contra uma allowlist. Aceite só os domínios que a aplicação atende e rejeite o resto com 400. No ASP.NET Core, configure AllowedHosts com seus domínios reais em vez de um curinga; no Django, configure ALLOWED_HOSTS. No servidor web, faça o virtual host padrão ser um catch-all que recusa a requisição em vez de servir a aplicação, por exemplo um bloco server do nginx com listen 80 default_server; e return 444;.
3. Confie em headers de encaminhamento só vindos dos seus proxies. Aceite X-Forwarded-Host e parecidos apenas de endereços de proxy conhecidos: KnownProxies ou KnownNetworks no ForwardedHeadersOptions do ASP.NET Core, uma lista específica de endereços em "trust proxy" no Express e USE_X_FORWARDED_HOST no Django só quando for necessário. Faça o proxy de borda sobrescrever esses headers com o valor real, em vez de repassar o que o cliente mandou.
4. Remova headers que você não usa. Se nada depende de X-Host ou X-Forwarded-Server, descarte-os na borda.
5. Faça o cache incluir na chave qualquer header que a aplicação use para montar respostas, ou não coloque essas respostas em cache.
6. Mantenha virtual hosts internos em listeners ou redes separados, e não apenas atrás de um valor de Host diferente.
Depois do deploy, teste de novo cada header de encaminhamento e o próprio Host, e confira o link de um e-mail de reset real.
Verifique o seu próprio site
Comece pelo scan passivo gratuito: não precisa de conta e você recebe uma nota de A a F cobrindo cabeçalhos, TLS, cookies, DNS e outras configurações que qualquer visitante consegue observar. Ele não envia payloads de ataque, então não confirma todas as classes de falha. O scan completo, disponível com uma conta gratuita, executa as verificações ativas, incluindo a descrita nesta página.