Knowledge Base
Host Header Injection — атаки через подмену заголовка Host
Host Header Injection
Категория: Web Application Security · Риск: medium
Host Header Injection
Что такое Host Header Injection
Заголовок `Host` в HTTP-запросе указывает, к какому виртуальному хосту обращается клиент. Если сервер использует значение заголовка `Host` для генерации ссылок (ссылки для сброса пароля, абсолютные URL в письмах) без проверки — атакующий может подменить его.
Сценарии атаки
Перехват ссылки для сброса пароля
POST /password-reset HTTP/1.1
Host: attacker.com ← подменённый заголовок
Content-Type: application/json
{"email": "victim@example.com"}
Если приложение строит ссылку как `$HOST/reset?token=...`, жертва получит письмо:
Для сброса пароля перейдите: https://attacker.com/reset?token=ABCD
Cache Poisoning
Если CDN кеширует ответ, включающий значение Host в тело (`<link href="https://{HOST}/style.css">`), атакующий может отравить кеш для других пользователей.
SSRF через X-Forwarded-Host
GET / HTTP/1.1
Host: example.com
X-Forwarded-Host: attacker.com
X-Forwarded-For: 127.0.0.1
Проверка уязвимости
# Проверка отражения Host в ответе
curl -si -H "Host: injected.example.com" https://example.com/
# Ищем injected.example.com в Location, Set-Cookie, теле ответа
# Проверка X-Forwarded-Host
curl -si -H "X-Forwarded-Host: injected.example.com" https://example.com/
# Безопасный результат: хост не отражается, или возвращается 400
Как защититься
Явная конфигурация разрешённых хостов
# Django
ALLOWED_HOSTS = ['example.com', 'www.example.com']
# FastAPI — проверка через middleware
from fastapi import Request, HTTPException
@app.middleware("http")
async def check_host(request: Request, call_next):
allowed = {'example.com', 'www.example.com'}
host = request.headers.get('host', '').split(':')[0]
if host not in allowed:
raise HTTPException(status_code=400, detail="Invalid host")
return await call_next(request)
// Laravel
// config/app.php нет встроенной защиты — используйте:
if (!in_array($_SERVER['HTTP_HOST'], ['example.com', 'www.example.com'])) {
http_response_code(400);
exit;
}
Nginx — явный server_name
server {
listen 443 ssl;
server_name example.com www.example.com;
# Запрещает запросы с другим Host
if ($host !~* ^(example\.com|www\.example\.com)$) {
return 444;
}
}
# Дефолтный блок — отклоняет все остальные Host
server {
listen 443 ssl default_server;
ssl_certificate /etc/nginx/ssl/dummy.crt;
ssl_certificate_key /etc/nginx/ssl/dummy.key;
return 444;
}
Генерация абсолютных URL без Host заголовка
# Задайте BASE_URL явно в конфиге, не полагайтесь на request.host
BASE_URL = "https://example.com"
def make_reset_link(token: str) -> str:
return f"{BASE_URL}/reset?token={token}"
Связанные проверки
- [Open Redirect](/kb/web_app_security/safe-redirect-handling-scanner)
- [SSRF / DNS Rebinding](/kb/web_app_security/scanner-ssrf-dns-rebinding)
- [CORS Misconfiguration](/kb/web_app_security/cors-misconfiguration-check)