Domain IP Lookup

同一个地址,四种写法

127.0.0.1标准点分十进制表示
2130706433同一地址的纯整数形式
0x7f.0.0.1同一地址的十六进制形式
127.1同一地址的简写形式
安全

SSRF 攻击详解:DNS 如何被利用

3 分钟阅读

服务端请求伪造(SSRF)指的是,攻击者让服务器代其发起一次 HTTP(或其他网络)请求,目的地由攻击者而非应用的开发者选定。一个典型的入口是:某个功能会抓取用户提供的 URL,比如图片导入、Webhook 目标、链接预览,而攻击者提供的 URL 指向的不是公开资源,而是内部基础设施。

DNS 在攻击中的位置

天真的防御做法,是检查所提供 URL 的主机名看起来是否像内部地址。这种做法很容易被绕过:攻击者注册一个公网域名,把它的 DNS 记录指向内部 IP,然后交给您的服务器一个看上去完全正常的主机名。您的校验看到的是域名而不是 IP,危险的部分要等 DNS 解析发生之后才会出现,而这一步往往深藏在实际发出请求的 HTTP 客户端库内部,远在任何前置校验步骤之后。

真正的防护是什么样的

  • 在发出任何请求之前,自己显式地解析主机名,不要让 HTTP 客户端在您看不见的地方代为解析。
  • 把每一个解析出的地址(是全部,一个域名可能返回多个)与私有/环回/链路本地/云元数据拦截名单逐一核对。
  • 只要有任何一个解析出的地址不被允许,就拒绝该请求,而不是只检查返回的第一个。
  • 在请求发出时再次校验,而不是只在输入时校验,以堵上另文所述的 DNS 重绑定漏洞,实践中 SSRF 与重绑定经常被组合使用。

云元数据端点在这里值得特别提一下:在大多数云服务商上,从虚拟机内部向某个特定的链路本地地址发起请求,可能返回凭据、实例元数据或配置信息,而这些内容本不应从机器之外访问到。SSRF 与元数据端点目标相结合,是现实中最常见、影响最大的攻击链之一,而它每一次都始于一个看起来平平无奇的域名。

只检查字符串、不检查地址的过滤器无效

一个 IP 地址的有效文本写法,比大多数校验代码考虑到的要多。如果过滤器只是对“127.0.0.1”或“localhost”做字符串匹配,下面这些替代写法就会原封不动地一路放行,因为它们看起来都不像被检查的那个字符串。

写法示例解析为
标准点分十进制127.0.0.1127.0.0.1
纯十进制整数2130706433127.0.0.1
八进制0177.0.0.1127.0.0.1
十六进制0x7f.0.0.1127.0.0.1
简写形式(少于 4 段)127.1127.0.0.1

唯一可靠的防御,是先把地址解析成它真正的数值,再拿数值去对照拦截名单,本工具自带的解析器采用的正是这种方式,而不是对地址碰巧使用的写法做模式匹配。无论原始主机名的记录是以何种方式编码的,解析器返回的都是规范化之后的地址,这恰恰是先解析、再校验解析结果,比试图校验攻击者可能选用的各种原始字符串更稳健的原因。

重定向是另一种常见的绕过方式

即使系统能够正确解析并校验最初的 URL,仍然可能被 HTTP 重定向蒙混过关。对一个经过批准的公网 URL 发出的请求,可以用 302 响应指向某个内部地址,而自动跟随重定向的 HTTP 客户端(大多数库的默认行为)会毫不犹豫地发出第二次请求,完全不会重新执行第一次通过的那次校验。任何只在最前面校验一次、之后就让底层 HTTP 客户端自行处理重定向的 SSRF 防御,都存在一个与 DNS 解析所造成的漏洞形态完全相同的缺口,修复方法也同样:在跟随任何重定向之前,再次显式校验,而不要想当然地认为曾经通过一次的 URL 会一直指向安全的地方。

需要查看某个域名的公网 DNS 地址?使用 Domain IP Lookup 工具。