> - 原文地址：[What is Server-Side Request Forgery (SSRF)?](https://www.acunetix.com/blog/articles/server-side-request-forgery-vulnerability/)
> - 原文作者：[Ian Muscat](https://www.acunetix.com/blog/author/ianmuscat/)
> - 译文出自：[掘金翻译计划](https://github.com/xitu/gold-miner)
> - 本文永久链接：[https://github.com/xitu/gold-miner/blob/master/article/2021/server-side-request-forgery-vulnerability.md](https://github.com/xitu/gold-miner/blob/master/article/2021/server-side-request-forgery-vulnerability.md)
> - 译者：[MoonBall](https://github.com/MoonBall)
> - 校对者：[PassionPenguin](https://github.com/PassionPenguin)、[kamly]()

# 什么是服务端请求伪造（SSRF）？

![](https://www.acunetix.com/wp-content/uploads/2019/02/ssrf_banner-910x273.png)

服务端请求伪造（SSRF）漏洞让攻击者从存在漏洞的应用程序的后端服务中发送恶意请求。攻击者通常使用 SSRF 攻击位于防火墙之后的内部系统，这些内部系统是不能从外部网络访问的。攻击者也可以利用 SSRF 访问通过服务器的环回接口（(127.0.0.1）可访问的服务。

当攻击者可以完全控制或部分控制应用程序发送的请求时，SSRF 漏洞就出现了。常见的例子是攻击者能控制第三方服务的 URL，并且应用程序将发起该 URL 对应的请求。

以下是一个 PHP 例子，它易遭受 SSRF 攻击。

```php
<?php

/**
* 检查是否设置了 GET 变量 'url'
* 例如 - http://localhost/?url=http://testphp.vulnweb.com/images/logo.gif
*/
if (isset($_GET['url'])){
$url = $_GET['url'];

/**
* 发起易遭受 SSRF 攻击的请求因为
* 在发起请求之前
* 没有对 $url 做验证
*/
$image = fopen($url, 'rb');

/**
* 发送正确的响应头
*/
header("Content-Type: image/png");

/**
* 响应图片的内容
*/
fpassthru($image);}
```

在上面的例子中，攻击者可以完全控制 **url** 参数。攻击者可以向因特网上的任意网站和被攻击服务器（**localhost**）上的资源发起 GET 请求。

在下面的例子中，攻击者向 Apache HTTP 服务发起一个请求。该 Apache HTTP 服务开启了 **mode_status** 模式（该模式默认是开启的）。

```http request
GET /?url=http://localhost/server-status HTTP/1.1
Host: example.com
```

攻击者也可以使用 SSRF 向 web 服务器有权访问的其他内部资源发出请求，尽管它们不是公开可访问的。例如，攻击者可以访问类似 AWS/[Amazon EC2](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html) 和 [OpenStack](https://docs.openstack.org/admin-guide/compute-networking-nova.html) 的云服务实例的元数据。攻击者甚至可以利用 SSRF 发挥创意，[对内部 IP 进行端口扫描](https://www.acunetix.com/blog/articles/ssrf-vulnerability-used-to-scan-the-web-servers-network/)。

```http request
GET /?url=http://169.254.169.254/latest/meta-data/ HTTP/1.1
Host: example.com
```

除了 **http://** 和 **https://** URL 协议之外，攻击者可以利用鲜为人知的或古老的 URL 协议访问本地系统或内部网络上的文件。

下面的例子使用了 **file:///** 协议。

```http request
GET /?url=file:///etc/passwd HTTP/1.1
Host: example.com
```

部分应用可能允许攻击者使用更多奇怪的 URL 协议。比如，如果应用使用 cURL 发起请求，那么攻击者可以使用 **dict://** URL 协议向任意的主机和端口发起请求，并发送自定义数据。

```http request
GET /?url=dict://localhost:11211/stat HTTP/1.1
Host: example.com
```

上面的请求使得应用程序连接 **localhost** 的 11211 端口，并发送 `stat` 字符串。端口 11211 是 [Memcached](https://memcached.org/) 的默认端口，该端口通常不会对外暴露。

## 检查服务端请求伪造

为了自动检测服务端请求伪造，你需要使用一个中间服务，因为检查这种漏洞需要一种外部可访问的并存在时延的方式。Acunetix 通过将 [AcuMonitor](https://www.acunetix.com/vulnerability-scanner/acumonitor-technology/) 作为中间服务解决该问题。

在扫描期间，Acunetix 向不同的 AcuMonitor URL 发起请求。如果 AcuMonitor 在这些不同的 URL 中收到一个请求，它将通知 Acunetix。然后 Acunetix 经发出 SSRF 警报。

下图是使用 AcuMonitor 的 Acunetix 扫描结果，它检查了服务端请求伪造。该警报包含 HTTP 请求的信息。它包括发起请求的服务器 IP 地址和请求中携带的 `User-Agent` 字符串（如果存在）。这些信息可以帮助开发者定位问题源头并修复问题。

![](https://www.acunetix.com/wp-content/uploads/2019/02/ssrf_screenshot-910x673.png)

## 消除服务端请求伪造

将简单的黑名单和正则表达式应用于用户输入是消除 SSRF 攻击的一种糟糕方法。通常，黑名单是一种几乎无效的安全控制手段。因为攻击者总是可以找到方法去绕过它们。在这个例子中，攻击者可以使用 HTTP 重定向、通配符 DNS 服务（比如 **xip.io**）或者甚至是 [可替代的 IP 编码](http://www.pc-help.org/obscure.htm)实现绕过黑名单。

### 白名单和 DNS 解析

最稳健的避免服务端请求伪造的方式是将你的应用需要访问的 DNS 名称和 IP 地址添加到白名单中。如果白名单机制不能满足你的需求，并且你必须依赖黑名单机制，那么对用户输入进行合理的校验就显得非常重要。比如，不允许向私有的 IP 地址发起请求（私用 IP 地址参考 [RFC 1918](https://tools.ietf.org/html/rfc1918)）。

然而，在使用黑名单的场景中，正确的消除 SSRF 的方式将因应用而异。换句话说，没有使用黑名单机制修复 SSRF 漏洞的银弹，因为它高度依赖应用功能和业务需求。

### 处理响应

避免响应数据泄露给攻击者，你必须确保收到的响应是期望的内容。在任何情况下，都不应将服务器发送的请求的原始响应体传递给客户端。

### 禁用不使用的 URL 协议

如果你的应用仅使用 HTTP 或 HTTPS 发起请求，那么就只允许这些 URL 协议。如果你禁用掉不使用的 URL 协议，攻击者将不能使用具有潜在危险的协议发起请求，比如：**file:///**, **dict://**, **ftp://** 和 **gopher://**。

### 内网服务进行身份认证

默认情况下，类似于 Memcached、Redis、Elasticsearch、MongoDB 的服务不要求身份认证。攻击者可以利用服务端请求伪造漏洞，无需身份认证便能访问这些服务。因此，为了确保应用程序的安全，最好尽可能启用身份认证，即使是本地网络上的服务。

> 如果发现译文存在错误或其他需要改进的地方，欢迎到 [掘金翻译计划](https://github.com/xitu/gold-miner) 对译文进行修改并 PR，也可获得相应奖励积分。文章开头的 **本文永久链接** 即为本文在 GitHub 上的 MarkDown 链接。

---

> [掘金翻译计划](https://github.com/xitu/gold-miner) 是一个翻译优质互联网技术文章的社区，文章来源为 [掘金](https://juejin.im) 上的英文分享文章。内容覆盖 [Android](https://github.com/xitu/gold-miner#android)、[iOS](https://github.com/xitu/gold-miner#ios)、[前端](https://github.com/xitu/gold-miner#前端)、[后端](https://github.com/xitu/gold-miner#后端)、[区块链](https://github.com/xitu/gold-miner#区块链)、[产品](https://github.com/xitu/gold-miner#产品)、[设计](https://github.com/xitu/gold-miner#设计)、[人工智能](https://github.com/xitu/gold-miner#人工智能)等领域，想要查看更多优质译文请持续关注 [掘金翻译计划](https://github.com/xitu/gold-miner)、[官方微博](http://weibo.com/juejinfanyi)、[知乎专栏](https://zhuanlan.zhihu.com/juejinfanyi)。
