# 访问控制漏洞与权限提升

在本节中，我们将讨论什么是访问控制安全，描述权限提升和访问控制可能引起的漏洞类型，并总结如何防止这些漏洞。

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

## 什么是访问控制？

访问控制（或授权）是对谁（或什么）可以执行尝试的操作或访问所请求的资源进行约束的应用。在Web应用程序的背景下，访问控制依赖于认证和会话管理：

* **认证**用于确定用户身份，并确认他们就是他们声称的那个人。
* **会话管理**用于确定后续的HTTP请求是由同一用户发起的。
* **访问控制**决定用户是否被允许执行他们试图执行的操作。

访问控制失效是一种常见且经常是严重的安全漏洞。访问控制的设计和管理是一个复杂和动态的问题，它将业务、组织和法律约束应用于技术实现。访问控制的设计决策必须由人类而不是技术做出，因此出错的可能性很高。

从用户的角度看，访问控制可以分为以下几类：

* 垂直访问控制
* 水平访问控制
* 上下文相关的访问控制

![](/files/XoPtnbepiR7UHRgTmaZT)

> **阅读更多**
>
> * [访问控制安全模型](/wsa/server-side/access-control/security-models.md)

### 垂直访问控制

垂直访问控制是一种机制，用于限制对其他类型的用户无法使用的敏感功能的访问。

通过垂直访问控制，不同类型的用户可以访问不同的应用程序功能。例如，管理员可能能够修改或删除任意用户的账户，而普通用户无权访问这些操作。垂直访问控制可以是安全模型更细粒度的实现，皆在执行业务策略，如职责分离和最小权限。

### 水平访问控制

水平访问控制是一种机制，它将资源的访问限制在那些被明确允许访问这些资源的用户范围内。

通过水平访问控制，不同的用户可以访问同一类型资源的子集。例如，银行应用程序将允许用户查看他们自己账户的交易并进行支付，但不能查看任何其他用户的账户。

### 上下文相关的访问控制

上下文相关的访问控制根据应用程序的状态或用户与之的交互来限制对功能和资源的访问。

上下文相关的访问控制可防止用户以错误的顺序执行操作。例如，零售网站可能会阻止用户在支付后修改他们购物车的内容。

## 失效的访问控制示例

当用户实际上可以访问他们不应该能访问的某些资源或执行他们不应该能执行的某些操作时，就会存在失效的访问控制漏洞。

### 垂直权限提升

如果用户可以访问他们不被允许访问的功能，那么这就是垂直权限提升。例如，如果一个非管理员用户实际上可以访问到一个可以删除用户账户的管理页面，那这就是垂直权限提升。

#### 未受保护的功能

最基本的，当应用程序不对敏感功能实施任何保护时，就会出现垂直权限升级。例如，管理功能可能从管理员的欢迎页面链接，而不是从用户的欢迎页面链接。但是，用户可能只需直接浏览到相关的管理URL，就能访问到管理功能。

例如，一个网站可能在以下URL托管敏感功能：

```
https://insecure-website.com/admin
```

实际上，可能任何用户都可以访问该功能，而不仅仅是在用户界面中有该功能链接的管理员用户。在某些情况下，管理URL可能在其他地方公开，如`robots.txt`文件：

```
https://insecure-website.com/robots.txt
```

即使URL没有在任何地方公开，可能攻击者也能够使用词表来暴力破解敏感功能的位置。

> **LAB**
>
> [未受保护的管理功能](https://portswigger.net/web-security/access-control/lab-unprotected-admin-functionality)

在某些情况下，敏感功能并没有得到有力的保护，而是通过给它一个不太可预测的URL来隐藏：所谓的隐蔽性安全。仅仅隐藏敏感功能并不能提供有效的访问控制，因为用户仍然可能以各种方式发现混淆的URL。

例如，考虑一个在以下URL托管管理功能的应用程序：

```
https://insecure-website.com/administrator-panel-yb556
```

这可能无法让攻击者直接猜测到。但是，应用程序仍可能会将URL泄露给用户。例如，URL可能会在JavaScript中被公开，该JavaScript根据用户的角色构建用户界面：

```javascript
<script>
var isAdmin = false;
if (isAdmin) {
	...
	var adminPanelTag = document.createElement('a');
	adminPanelTag.setAttribute('https://insecure-website.com/administrator-panel-yb556');
	adminPanelTag.innerText = 'Admin panel';
	...
}
</script>
```

如果用户是管理用户，此脚本将添加一个指向用户UI的链接。但包含URL的脚本对所有用户都是可见的，无论其角色如何。

> **LAB**
>
> [未受保护的管理功能，其URL不可预测](https://portswigger.net/web-security/access-control/lab-unprotected-admin-functionality-with-unpredictable-url)

#### 基于参数的访问控制方法

一些应用程序在登录时确定用户的访问权限或角色，然后将这些信息存储在用户可控的位置，如隐藏字段、Cookie或预设的查询字符串参数。应用程序根据提交的值做出后续的访问控制决策。例如：

```
https://insecure-website.com/login/home.jsp?admin=true
https://insecure-website.com/login/home.jsp?role=1
```

这种方法从根本上来说是不安全的，因为用户可以简单地修改值并获取对他们未被授权的功能的访问权限，例如管理功能。

> **LAB**
>
> [通过请求参数控制用户角色](https://portswigger.net/web-security/access-control/lab-user-role-controlled-by-request-parameter)

> **LAB**
>
> [用户角色可以在用户个人资料中修改](https://portswigger.net/web-security/access-control/lab-user-role-can-be-modified-in-user-profile)

#### 平台配置不当导致的访问控制失效

一些应用程序在平台层面，通过基于用户角色来限制对特定URL和HTTP方法的访问来实施访问控制。例如，应用程序可能配置如下规则：

```
DENY: POST, /admin/deleteUser, managers
```

此规则拒绝managers组中的用户`POST`方法访问`/admin/deleteUser` URL。在这种情况下，可能会出现各种问题，导致访问控制的绕过。

一些应用框架支持各种非标准HTTP标头，这些标头可以用来覆盖原始请求中的URL，例如`X-Original-URL`和`X-Rewrite-URL`。如果一个网站使用严格的前端控制来限制基于URL的访问，但是应用程序允许通过请求标头覆盖URL，那么也许可以通过如下请求绕过访问控制：

```http
POST / HTTP/1.1
X-Original-URL: /admin/deleteUser
...
```

> **LAB**
>
> [基于URL的访问控制可以被绕过](https://portswigger.net/web-security/access-control/lab-url-based-access-control-can-be-circumvented)

另一种攻击可能与请求中使用的HTTP方法有关。上面的前端控制根据URL和HTTP方法来限制访问。一些网站在进行某些操作时，对于使用其他HTTP请求方法比较宽容。如果攻击者可以使用`GET`（或其他）方法对受限制的URL进行操作，那么他们就可以绕过平台层面实现的访问控制。

> **LAB**
>
> [基于方法的访问控制可以被绕过](https://portswigger.net/web-security/access-control/lab-method-based-access-control-can-be-circumvented)

#### URL匹配不一致导致的访问控制失效

在路由传入请求时，不同的网站对于路径与已定义端点的匹配程度各有不同。例如，它们可能容忍大小写不一致，因此一个对`/ADMIN/DELETEUSER`的请求仍可能会映射到相同的`/admin/deleteUser`端点。这本身并不是问题，但如果访问控制机制的容忍度较低，可能会将这它们视为两个不同的端点，从而无法执行适当的限制。

如果使用Spring框架的开发人员启用了`useSuffixPatternMatch`选项，也会出现类似的差异。这将允许具有任意文件后缀名的路径映射到没有文件后缀名的等效端点。换句话说，一个对`/admin/deleteUser.anything`的请求仍然会匹配`/admin/deleteUser`这个模式。在Spring 5.3之前，该选项默认启用。

在其他系统中，你可能会遇到`/admin/deleteUser`和`/admin/deleteUser/`是否被视为不同端点的差异。在这种情况下，只需在路径后添加一个尾部斜杠，即可绕过访问控制。

### 水平权限提升

当一个用户能够访问属于其他用户的资源而不是属于自己的同类型资源时，就会出现水平权限提升。例如，如果一个员工只能访问自己的就业和工资记录，但实际上也可以访问其他员工的记录，那么这就是水平权限提升。

水平权限提升攻击可能使用与垂直权限提升类似的利用方法。例如，用户通常可以使用以下URL访问自己的账户页面：

```
https://insecure-website.com/myaccount?id=123
```

现在，如果攻击者修改`id`参数值为另一个用户的值，那么攻击者就可能访问到另一个用户的账户页面，以及关联的数据和功能。

> **LAB**
>
> [由请求参数控制的用户ID](https://portswigger.net/web-security/access-control/lab-user-id-controlled-by-request-parameter)

在某些应用中，可被利用的参数没有可预测的值。例如，应用程序可能使用全局唯一标识符（GUID）来识别用户，而不是递增的数字。在这里，攻击者可能无法猜测或预测其他用户的标识符。然而，其他用户的GUID可能在应用程序的其他地方被泄露，如用户留言或评论。

> **LAB**
>
> [由请求参数控制且不可预测的用户ID](https://portswigger.net/web-security/access-control/lab-user-id-controlled-by-request-parameter-with-unpredictable-user-ids)

在某些情况下，应用程序确实会检测到用户不被允许访问资源，并返回一个登录页面的重定向。但是，包含重定向的响应可能仍包含一些属于目标用户的敏感数据，因此攻击仍会成功。

> **LAB**
>
> [由请求参数控制的用户ID，在重定向中泄露数据](https://portswigger.net/web-security/access-control/lab-user-id-controlled-by-request-parameter-with-data-leakage-in-redirect)

### 水平到垂直权限提升

通常，通过入侵一个更有权限的用户，水平权限提升攻击可以转变为垂直权限提升。例如，水平提升可能允许攻击者重置或捕获属于另一个用户的密码。如果攻击者以管理用户为目标并入侵其帐户，那么他们就可以获得管理访问权限，从而进行垂直权限提升。

例如，攻击者可能会使用已经描述过的水平权限提升中的参数篡改技术，访问到另一个用户的账户页面：

```
https://insecure-website.com/myaccount?id=456
```

如果目标用户是一个应用程序管理员，那么攻击者将获得对管理账户页面的访问权限。这个页面可能会泄露管理员的密码或提供修改密码的方法，或者可能提供对特权功能的直接访问。

> **LAB**
>
> [由请求参数控制的用户ID，并泄露密码](https://portswigger.net/web-security/access-control/lab-user-id-controlled-by-request-parameter-with-password-disclosure)

### 不安全的直接对象引用

不安全的直接对象引用（IDOR）是访问控制漏洞的一个子类。当应用程序使用用户提供的输入直接访问对象，并且攻击者可以修改输入以获得未经授权的访问时，就会产生IDOR。它因出现在OWASP 2007十大安全漏洞中而广为人知，尽管它只是众多可能导致访问控制被绕过的实现错误之一。

> **LAB**
>
> [不安全的直接对象引用](https://portswigger.net/web-security/access-control/lab-insecure-direct-object-references)

> **阅读更多**
>
> * [不安全的直接对象引用 (IDOR)](/wsa/server-side/access-control/idor.md)

### 多步骤流程中的访问控制漏洞

很多网站会通过一系列步骤来实现重要的功能。通常在需要捕获各种输入或选项，或者用户需要在执行操作之前审查和确认细节时采取这种做法。例如，更新用户详细信息的管理功能可能涉及以下步骤：

1. 加载特定用户详细信息的表单。
2. 提交更改。
3. 审核更改并确认。

有时，网站会对其中的一些步骤实施严格的访问控制，但忽略其他步骤。例如，假设访问控制正确应用于了第一步和第二步，但没有应用于第三步。这样，网站假设用户只有在完成了已受到适当控制的前两步之后，才会到达第三步。在这里，攻击者可以通过跳过前两步，并直接提交带有所需参数的第三步请求，来获得对该功能的未授权访问。

> **LAB**
>
> [多步骤流程其中的一个步骤没有访问控制](https://portswigger.net/web-security/access-control/lab-multi-step-process-with-no-access-control-on-one-step)

### 基于Referer的访问控制

一些网站基于HTTP请求中提交的`Referer`标头进行访问控制。`Referer`标头通常由浏览器添加到请求中，以表明发起请求的页面。

例如，假设一个应用程序在`/admin`主管理页面上强制执行访问控制，但是对于`/admin/deleteUser`等子页面，只检查`Referer`标头。如果`Referer`标头包含主`/admin` URL，那么请求会被允许。

在这种情况下，由于`Referer`标头可以完全由攻击者控制，他们可以伪造对敏感子页面的直接请求，并提供所需的`Referer`标头，从而获取未授权的访问。

> **LAB**
>
> [基于Referer的访问控制](https://portswigger.net/web-security/access-control/lab-referer-based-access-control)

### 基于位置的访问控制

一些网站根据用户的地理位置对资源实施访问控制。这可以应用于适用州立法或业务限制的银行应用程序或媒体服务。这些访问控制通常可以通过使用Web代理、VPN或操纵客户端地理定位机制来绕过。

## 如何防范访问控制漏洞

访问控制漏洞通常可以通过采取深度防御方法并应用以下原则来防范：

* 永远不要仅依靠混淆来进行访问控制。
* 除非资源打算供公开访问，否则默认拒绝访问。
* 尽可能使用单一的、全局的应用机制来实施访问控制。
* 在代码级别，强制要求开发人员声明每个资源允许的访问权限，并默认拒绝访问。
* 彻底审计和测试访问控制，以确保它们按设计运行。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://web-sec.gitbook.io/wsa/server-side/access-control/index.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
