# 服务器端请求伪造（SSRF）

在本节中，我们将讲解什么是服务器端请求伪造，描述一些常见示例，并解释如何发现和利用各种类型的SSRF漏洞。

## 什么是SSRF？

服务器端请求伪造（也称为SSRF）是一种Web安全漏洞，它允许攻击者诱导服务器端应用程序向非预期的位置发起请求。

在典型的SSRF攻击中，攻击者可以使服务器连接到组织基础设施内的内部服务。在其他情况中，攻击者能够强迫服务器连接到任意的外部系统，从而可能泄露授权凭证等敏感数据。

![](https://2165487371-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FfahSMMYUzmqmE8SfCaax%2Fuploads%2Fgit-blob-a8f409079a590f912f7f70c86e0f34a76fa00b11%2Fserver-side-request-forgery.svg?alt=media)

> **Labs**
>
> 如果你已经熟悉SSRF漏洞背后的基本概念，并且只想在一些真实的、故意易受攻击的目标上练习利用它们，你可以从下面的链接访问本主题中的所有实验。
>
> * [查看所有SSRF实验](https://portswigger.net/web-security/all-labs#server-side-request-forgery-ssrf)

## SSRF攻击有什么影响？

一次成功的SSRF攻击通常会导致对组织内部的数据进行未授权的操作或访问，无论是在存在漏洞的应用程序本身，还是在应用程序可以与之通信的其他后端系统上。在某些情况下，SSRF漏洞可能允许攻击者执行任意命令。

导致连接到外部第三方系统的SSRF漏洞利用可能会导致恶意转发攻击，而这些攻击看似是来自托管存在漏洞的应用程序的组织。

## 常见的SSRF攻击

SSRF攻击通常利用信任关系从存在漏洞的应用程序升级攻击并执行未授权的操作。这些信任关系可能与服务器本身有关，也可能与同一组织内的其他后端系统有关。

### 针对服务器本身的SSRF攻击

在针对服务器本身的SSRF攻击中，攻击者诱导应用程序通过其环回网络接口向托管该应用程序的服务器发起HTTP请求。通常涉及提供一个带有主机名的URL，如`127.0.0.1`（一个指向环回适配器的保留IP地址）或`localhost`（同一适配器的常用名称）。

例如，考虑一个购物应用程序，它允许用户查看一个商品在特定商店的库存情况。为了提供库存信息，应用程序必须根据产品和商店的情况查询不同的后端REST API。该功能是通过前端HTTP请求将URL传递到相关的后端API来实现的。因此，当用户查看一个商品的库存状态时，他们的浏览器会发出如下请求：

```http
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=http://stock.weliketoshop.net:8080/product/stock/check%3FproductId%3D6%26storeId%3D1
```

这会导致服务器向指定的URL发起请求，检索库存状态，并将其返回给用户。

这种情况下，攻击者可以修改请求，指定服务器本身本地的URL。例如：

```http
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=http://localhost/admin
```

在这里，服务器将获取`/admin` URL的内容并将其返回给用户。

当然，攻击者现在可以直接访问`/admin` URL。但管理功能通常只有经过适当身份验证的用户才能访问。因此直接访问URL的攻击者将不会看到任何感兴趣的内容。然而，当对`/admin` URL的请求来自本地机器本身时，正常的访问控制被绕过。应用程序授予对管理功能的完全访问，因为请求看起来是来自一个受信任的位置。

> **LAB**
>
> [针对本地服务器的基础SSRF](https://portswigger.net/web-security/ssrf/lab-basic-ssrf-against-localhost)

应用程序为什么会以这种方式运行，隐式地信任来自本地机器的请求？出现这种情况的原因有很多：

* 访问控制检查可能在位于应用服务器前面的另一个组件中实现。当与服务器本身建立连接时，检查将被绕过。
* 出于灾难恢复的目的，应用程序可能允许来自本地机器的任何用户在不登录的情况下进行管理访问。这为管理员在丢失凭证的情况下提供了一种恢复系统的方式。这里的假设是，只有完全受信任的用户才会直接从服务器本身登录。
* 管理界面可能在与主应用程序不同的端口号上监听，因此用户可能无法直接访问。

这种信任关系，即来自本地机器的请求与普通请求相比被不同地处理，往往是导致SSRF成为严重漏洞的原因。

### 针对其他后端系统的SSRF攻击

由于服务器端请求伪造而经常出现的另一种信任关系是，应用服务器能够与用户无法直接访问的其他后端系统进行交互。这些系统通常有不可路由的私有IP地址。由于后端系统通常受到网络拓扑的保护，因此它们的安全状况往往较弱。在很多情况下，内部的后端系统包含敏感功能，任何能够与系统交互的人都可以在无需认证的情况下访问这些功能。

在前面的示例中，假设后端URL `https://192.168.0.68/admin`处有一个管理接口。在这里，攻击者可以通过提交如下请求来利用SSRF漏洞访问管理接口：

```http
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=http://192.168.0.68/admin
```

> **LAB**
>
> [针对其他后端系统的基础SSRF](https://portswigger.net/web-security/ssrf/lab-basic-ssrf-against-backend-system)

## 绕过常见的SSRF防御措施

常见的情况是，包含SSRF行为的应用程序都有旨在防止恶意利用的防御措施。然而，这些防御措施往往是可以被绕过的。

### 基于黑名单输入过滤的SSRF

一些应用程序会阻止包含`127.0.0.1`和`localhost`之类的主机名，或者敏感的URL路径，如`/admin`。在这种情况下，通常你可以通过使用各种技术来绕过过滤：

* 使用`127.0.0.1`的替代IP表示，例如`2130706433`、`017700000001`或`127.1`。
* 注册一个你自己的域名，它将解析为`127.0.0.1`。为此，你可以使用`spoofed.burpcollaborator.net`。
* 使用URL编码或大小写变化来混淆被阻止的字符串。
* 提供一个由你控制的URL，并将其重定向到目标URL。尝试使用不同的重定向代码，以及目标URL的不同协议。例如，在重定向期间将`http:`切换为`https:`已被证明可以绕过某些反SSRF的过滤。

> **LAB**
>
> [基于黑名单输入过滤的SSRF](https://portswigger.net/web-security/ssrf/lab-ssrf-with-blacklist-filter)

### 基于白名单输入过滤的SSRF

一些应用程序只允许输入与白名单中的值相匹配、以某些值开头或包含某些值。在这种情况下，有时可以通过利用URL解析中的一致性来绕过过滤。

URL规范包含了很多在对URL进行自定义的解析和验证时容易被忽略的特性：

* 你可以在主机名之前使用`@`字符将凭证嵌入URL中。例如：

  ```
  https://expected-host:fakepassword@evil-host
  ```
* 你可以使用`#`字符来表示URL片段。例如：

  ```
  https://evil-host#expected-host
  ```
* 你可以利用DNS命名层次结构，将所需输入放入由你控制的完全限定域名中。例如：

  ```
  https://expected-host.evil-host
  ```
* 你可以对字符进行URL编码以混淆URL解析代码。如果实现过滤的代码和执行后端HTTP请求的代码处理URL编码字符的方式不同，那么这种方法尤其有用。请注意，你也可以尝试对字符进行双重编码；一些服务器会对收到的输入进行递归URL解码，这可能会导致进一步的差异。
* 你可以将这些技术结合起来使用。

> **LAB**
>
> [基于白名单输入过滤的SSRF](https://portswigger.net/web-security/ssrf/lab-ssrf-with-whitelist-filter)

> **阅读更多**
>
> * [SSRF的新时代](https://portswigger.net/blog/top-10-web-hacking-techniques-of-2017#1)

### 通过开放重定向绕过SSRF过滤

有时候，可以通过利用开放重定向漏洞来绕过任何基于过滤的防御措施。

在前面的SSRF示例中，假设用户提交的URL经过严格验证，以防止对SSRF行为的恶意利用。然而，允许URL的应用程序中存在一个开放重定向漏洞。只要用于发起后端HTTP请求的API支持重定向，你就可以构造一个满足过滤要求的URL，并将请求重定向到所需的后端目标。

例如，假设应用程序存在一个开放重定向漏洞，其中包含以下URL：

```
/product/nextProduct?currentProductId=6&path=http://evil-user.net
```

返回一个重定向到：

```
http://evil-user.net
```

你可以利用这个开放重定向漏洞绕过URL过滤，并利用SSRF漏洞进行如下利用：

```http
POST /product/stock HTTP/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 118

stockApi=http://weliketoshop.net/product/nextProduct?currentProductId=6&path=http://192.168.0.68/admin
```

这个SSRF利用之所以有效，是因为应用程序首先会验证所提供的`stockAPI` URL是否属于允许的域，而它确实属于允许的域。然后，应用程序请求所提供的URL，从而触发开放重定向。应用程序追随重定向，并向攻击者选择的内部URL发起请求。

> **LAB**
>
> [通过开放重定向漏洞绕过带有过滤的SSRF](https://portswigger.net/web-security/ssrf/lab-ssrf-filter-bypass-via-open-redirection)

## 盲SSRF漏洞

盲SSRF漏洞是指应用程序能够被诱导向提供的URL发出后端HTTP请求，但后端请求的响应并未在应用程序的前端响应中返回。

盲SSRF漏洞通常更难利用，但有时可以导致对服务器或其他后端组件完全的远程代码执行。

> **阅读更多**
>
> * [发现并利用盲SSRF漏洞](https://web-sec.gitbook.io/wsa/server-side/ssrf/blind)

## 发现隐藏的SSRF漏洞攻击面

大多数服务器端请求伪造漏洞相对容易发现，因为应用程序的正常流量涉及包含完整URL的请求参数。其他类型的SSRF漏洞则较难定位。

### 请求中的部分URL

有时，应用程序仅将主机名或部分URL路径放入请求参数中。提交的值随后会在服务器端组合成一个完整的URL并发送请求。如果该值很容易被识别为主机名或URL路径，那么潜在的攻击面可能就很明显了。但是，由于你无法控制被请求的整个URL，因此作为完整SSRF的可利用性可能会受到限制。

### 数据格式内的URL

某些应用程序传输的数据格式，其规范允许包含URL，而这些URL可能会在数据解析时被请求。一个明显的例子就是XML数据格式，它在Web应用程序中被广泛用于客户端和服务器之间传输结构化数据。当一个应用程序接受XML格式的数据并对其进行解析时，它可能容易受到XXE注入的攻击，进而通过XXE受到SSRF的攻击。我们将在研究XXE注入漏洞时更详细地介绍这一问题。

### 通过Referer标头的SSRF

一些应用程序使用服务器端分析软件来跟踪访问者。这种软件通常会记录请求中的Referer标头，因为这对跟踪传入链接特别有用。分析软件通常会实际访问出现在Referer标头中的任何第三方URL。这样做往往是为了分析Referer站点的内容，包括传入链接中使用的锚文本。因此，Referer标头常常是SSRF漏洞的有效攻击面。有关涉及Referer标头的漏洞示例，请参阅[盲SSRF漏洞](https://web-sec.gitbook.io/wsa/server-side/ssrf/blind)。

> **阅读更多**
>
> * [破解镜头：瞄准辅助系统](https://portswigger.net/blog/cracking-the-lens-targeting-https-hidden-attack-surface#aux)
