服务器端请求伪造
当用户能使应用程序向攻击者确定的域发出 HTTP 请求时,就会出现服务器端请求伪造漏洞。如果应用程序可以访问专用/内部网络,攻击者也可以使应用程序向内部服务器发出请求。
我们将通过一些例子来进一步了解它的实际效果。
考虑一种应用程序接口,它可以从用户处获取 URL 并生成用户提供的 URL 的图片,例如用于预览或导出页面。
ts
let url = request.params.url;
let response = http.get(url);
let render = response.render();
return render.export();
由于 URL 参数由用户控制,攻击者可以随心所欲地访问任何 URL。在某些情况下,根据用于访问 URL 的库,甚至可以使用 "file://"方案访问本地文件。
在 AWS 上托管时,滥用 SSRF 漏洞的一种常见方式是使用该漏洞访问 AWS 元数据 API,其中可能包含 AWS API 的凭据。这可能导致进一步访问账户内的其他 AWS 资源,可想而知,这并不理想。
缓解
缓解 SSRF 漏洞有时非常棘手,这在很大程度上取决于相关代码试图实现的目标。根据不同的要求,可以采取不同的缓解措施。
避免用户自定义 URL
在某些情况下,您可能能够以一种不依赖于用户提供任意 URL 的方式实现某项功能。如果有可能的话,这是降低 SSRF 风险的最有效方法。
最小化能力
如果您要实现 PDF 导出功能,可能会倾向于简单地使用无头浏览器并对页面进行截图。考虑到浏览器的复杂性以及浏览器暴露的大量功能和攻击面,这种做法并不总是可取的。
为手头的工作使用合适的工具非常重要。在某些情况下,一个简单的 HTTP 客户端就足够了。总有些事情可以做,以尽量减少功能,从而减少可用的攻击面/载体。例如 HTTP 客户端:
- 禁用以下重定向功能
- 禁用 HTTPS 以外的所有方案
存在一些隐患
重定向和 iframe
防止在私有资源(IP 地址或内部主机名)上使用 SSRF 的常见方法是解析用户提供的 URL,并使用 "拒绝列表 "来阻止对敏感资源的访问。
值得注意的是,这种方法在大多数情况下并不有效,因为在客户端遵循 HTTP 重定向、HTML/JavaScript 重定向或可以呈现 iframe 等复杂元素的情况下,可以绕过这种方法。
攻击者可以通过 HTTP 301/302、HTML Meta 重定向、在加载时使用 Javascript 设置当前 URL 或嵌入显示内部资源的 iframe 等方式,将 URL 提供给托管页面的易受攻击应用程序,该页面会重定向到敏感资源。这实际上绕过了验证原始 URL 的任何尝试。
DNS 重绑定
另一种 "类型 "的重定向也可以通过 DNS 完成。防止 SSRF 攻击的一种常见方法是采取以下措施:
- 解析所提供的 URL
- 获取主机名,并进行 DNS 查询
- 如果 URL 解析到内部/私有 IP,则拒绝该 URL;如果 URL 解析到公共 IP,则接受该 URL
由于容易受到 "DNS 重绑定 "的影响,这种方法实际上并不有效。DNS 重绑定之所以有效,是因为当远程主机关闭 TCP 连接时,大多数网络协议栈(如 Linux 和 Windows 的协议栈)的标准行为。
当远程主机强行关闭连接时,它会在进行另一次 DNS 查询以重新解析 IP 地址后尝试重新连接。
这样,攻击者就可以进行以下操作:
- 为 "rebinding.attacker.com "创建一个 DNS 条目,该条目包含一个公共 IP 地址和一个开放的 HTTP 端口,且 TTL(Time-to-live)极短。
- 向有漏洞的应用程序提交 URL(例如:https://rebinding.attacker.com/)。它会检查以确保解析的 IP 不是私有 IP(其实不是),然后在认为安全的情况下继续执行请求的操作
- 一旦建立 HTTP 连接,"rebinding.acker.com "的 DNS 条目就会更改为内部 IP 地址
- HTTP 连接被强制关闭
- 这将导致应用程序重新解析 "rebinding.attacker.com "的 IP 地址,该地址现在指向一个内部 IP 地址
- 由于 IP 解析保护已经发生,而且 DNS 条目的重新解析和重新连接都是在内核中进行的,因此应用程序不会意识到 IP 已发生变化这一事实。
这实际上绕过了防止提供解析到私人 IP 地址的 URL 的保护措施。
IPv4 与 IPv6
绕过 "拒绝列表 "的另一种常见方法是使用 IPv6。由于所有 IPv4 地址都可以用 IPv6 地址来表示,因此通常可以通过使用 IPv6 地址来绕过拒绝列表,该地址也可以映射到想要访问的 IPv4 地址。