SSRF 会让服务器沦为不知情的代理
攻击者
构造请求 URL
存在漏洞的服务器
被 SSRF 诱骗而发起请求
169.254.169.254
元数据端点
凭据
返回给攻击者
云元数据端点:隐蔽的攻击面
各大云服务商都会为运行在其平台上的虚拟机提供实例元数据服务,通常通过链路本地地址 169.254.169.254 访问。在实例内部,只需向该地址发起一次简单的 HTTP 请求,就能获得实例的配置、网络详情,而在许多默认配置下,还能拿到分配给该实例的角色或身份所对应的临时安全凭证。
为什么它与 SSRF 结合时尤其危险
元数据端点本应只能由实例自身访问,并不对公网开放。但如果服务端进程被诱导向攻击者指定的地址发起 HTTP 请求(典型的 SSRF),而这个地址恰好就是元数据端点,攻击者就能让服务器取回它自己的云凭证,并通过响应原样交出。攻击者无需从外部直接访问元数据端点,因为存在漏洞的服务器会代为完成请求。
- 169.254.169.254 属于范围更大的 169.254.0.0/16 链路本地地址段,这个地址段永远不应被当作合法的公网 DNS 解析目标。
- 部分服务商已改用需要令牌的元数据服务版本,专门用来抬高简单 SSRF 的攻击门槛,但在应用层彻底阻止该地址,依然是更稳妥的防御方式。
- 这正是任何需要解析用户提供的域名的工具,都应当把链路本地地址与私有地址、环回地址段放在同一份拦截名单中的原因:它并不是某种次要的风险类别。
实践中的要点
任何代表用户解析并请求某个 URL 的系统,都必须把 169.254.169.254 以及它所在的整个链路本地地址段视为严格禁区,并且在发起实际请求的那一刻、每一次都要检查,无论这个地址是如何得到的(直接输入,还是通过一条直接指向它的 DNS 记录)。
这并非某一家云服务商独有
169.254.169.254 具体来说是 AWS、Google Cloud 和 Azure 采用的约定,但其背后的模式,即用一个链路本地地址向实例自身开放实例身份和凭证,几乎在所有主流云平台和容器平台上都以某种形式存在,有时是同一个地址,有时是服务商专用的地址。Kubernetes 集群通常也有各自的内部端点,类似元数据服务,可从 Pod 内部访问。常见云服务商的具体地址值得记住,但真正具有普适性的是这条原则:无论运行在哪个平台上,凡是会解析并抓取用户提供的 URL 的程序,都应把所有元数据类端点视为禁区。
IMDSv2:真正的缓解措施,而不只是过滤
多年来这种利用方式层出不穷,AWS 的应对是推出元数据服务的第二个版本 IMDSv2:读取任何元数据之前,必须先通过一次特殊的 PUT 请求获取会话令牌。关键在于,大多数有漏洞的代码路径所发出的 SSRF 触发式 GET 请求,无法复现这个 PUT 请求。
| IMDSv1 | IMDSv2 | |
|---|---|---|
| 请求类型 | 简单的 GET | 先用 PUT 获取令牌,再带着令牌发起 GET |
| 是否会被基本的 SSRF GET 利用? | 是 | 否:仅能发起 GET 的 SSRF 无法获取令牌 |
| 采用情况 | 许多账户上的旧版默认设置 | 可选启用或强制启用,取决于账户设置 |
这是一项有实质意义的改进,但出于向后兼容,许多账户上它仍需手动启用,而且它只保护元数据端点本身,对 SSRF 仍可能触达的其他所有私有地址和内部地址毫无作用。无论使用哪个版本的元数据服务,对解析出的地址进行应用层过滤依然是必不可少的。
需要查看某个域名的公网 DNS 地址?使用 Domain IP Lookup 工具。
相关阅读
同一个地址,四种写法
SSRF 攻击详解:DNS 如何被利用
服务端请求伪造往往只始于一个域名:您的服务器被诱骗去解析并请求它。本文说明 DNS 在其中扮演的角色以及真正有效的防御。
同一个域名,两个不同的答案
首次请求
解析为公网 IP
校验
通过,看起来安全
TTL 过期
数秒之后
第二次请求
解析为 127.0.0.1
什么是 DNS 重绑定?为什么值得关注
一个域名先解析到安全的公网地址,随后又解析到内部地址:DNS 重绑定让 DNS 本身成为攻击面。了解它的原理,以及唯一可靠的防御方法。
几乎每个 DNS 区域都会遇到的记录
什么是 CAA 记录?控制哪些 CA 可以签发证书
了解 DNS 证书颁发机构授权(CAA)记录如何指定被允许的证书签发机构,以及发布限制之前该如何规划,避免常见的 CAA 配置错误。