mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/network-services-pentesting/pentesting-web/graphql.md']
This commit is contained in:
parent
11169a6406
commit
31cd565438
@ -8,7 +8,7 @@ GraphQL 被 **强调** 为 REST API 的 **高效替代方案**,提供了一种
|
||||
|
||||
## GraphQL 和安全性
|
||||
|
||||
随着包括 GraphQL 在内的新技术的出现,新安全漏洞也随之而来。一个关键点是 **GraphQL 默认不包含身份验证机制**。开发者有责任实施这些安全措施。没有适当的身份验证,GraphQL 端点可能会向未认证的用户暴露敏感信息,构成重大安全风险。
|
||||
随着新技术的出现,包括 GraphQL,新的安全漏洞也随之出现。一个关键点是 **GraphQL 默认不包含身份验证机制**。开发者有责任实施这些安全措施。没有适当的身份验证,GraphQL 端点可能会向未认证的用户暴露敏感信息,构成重大安全风险。
|
||||
|
||||
### 目录暴力攻击和 GraphQL
|
||||
|
||||
@ -23,11 +23,11 @@ GraphQL 被 **强调** 为 REST API 的 **高效替代方案**,提供了一种
|
||||
- `/graphql/api`
|
||||
- `/graphql/graphql`
|
||||
|
||||
识别开放的 GraphQL 实例可以检查支持的查询。这对于理解通过端点可访问的数据至关重要。GraphQL 的自省系统通过详细说明模式支持的查询来促进这一点。有关更多信息,请参阅 GraphQL 文档中的自省:[**GraphQL: A query language for APIs.**](https://graphql.org/learn/introspection/)
|
||||
识别开放的 GraphQL 实例可以检查支持的查询。这对于理解通过端点可访问的数据至关重要。GraphQL 的自省系统通过详细说明模式支持的查询来促进这一点。有关更多信息,请参阅 GraphQL 关于自省的文档:[**GraphQL: A query language for APIs.**](https://graphql.org/learn/introspection/)
|
||||
|
||||
### 指纹识别
|
||||
|
||||
工具 [**graphw00f**](https://github.com/dolevf/graphw00f) 能够检测服务器使用的 GraphQL 引擎,并打印一些对安全审计员有用的信息。
|
||||
工具 [**graphw00f**](https://github.com/dolevf/graphw00f) 能够检测服务器使用的 GraphQL 引擎,并打印一些对安全审计员有帮助的信息。
|
||||
|
||||
#### 通用查询 <a href="#universal-queries" id="universal-queries"></a>
|
||||
|
||||
@ -57,7 +57,7 @@ query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofTy
|
||||
|
||||
**错误**
|
||||
|
||||
了解 **错误** 是否会被 **显示** 是很有趣的,因为它们将提供有用的 **信息。**
|
||||
了解**错误**是否会被**显示**是很有趣的,因为它们将提供有用的**信息。**
|
||||
```
|
||||
?query={__schema}
|
||||
?query={}
|
||||
@ -172,7 +172,7 @@ name
|
||||
|
||||
现在我们知道数据库中保存了哪种信息,让我们尝试 **提取一些值**。
|
||||
|
||||
在自省中,您可以找到 **可以直接查询的对象**(因为您不能仅仅因为对象存在就查询它)。在下面的图像中,您可以看到 "_queryType_" 被称为 "_Query_",而 "_Query_" 对象的一个字段是 "_flags_",这也是一种对象类型。因此,您可以查询标志对象。
|
||||
在自省中,您可以找到 **可以直接查询的对象**(因为您不能仅仅因为对象存在就查询它)。在下图中,您可以看到 "_queryType_" 被称为 "_Query_",而 "_Query_" 对象的一个字段是 "_flags_",这也是一种对象类型。因此,您可以查询标志对象。
|
||||
|
||||

|
||||
|
||||
@ -180,7 +180,7 @@ name
|
||||
|
||||
.png>)
|
||||
|
||||
您可以看到 "_Flags_" 对象由 **name** 和 **value** 组成。然后,您可以使用以下查询获取所有标志的名称和值:
|
||||
您可以看到 "_Flags_" 对象由 **name** 和 **value** 组成。然后,您可以使用查询获取所有标志的名称和值:
|
||||
```javascript
|
||||
query={flags{name, value}}
|
||||
```
|
||||
@ -204,7 +204,7 @@ query = { hiddenFlags }
|
||||
看起来它会使用类型为 _**Int**_ 的 "_**uid**_" 参数进行搜索。\
|
||||
无论如何,我们已经知道,在 [Basic Enumeration](graphql.md#basic-enumeration) 部分提出了一个查询,显示了所有所需的信息:`query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}`
|
||||
|
||||
如果你阅读提供的图像,当我运行该查询时,你会看到 "_**user**_" 有一个类型为 _Int_ 的 **arg** "_**uid**_"。
|
||||
如果你阅读提供的图像,当我运行该查询时,你会看到 "_**user**_" 有类型为 _Int_ 的 **arg** "_**uid**_"。
|
||||
|
||||
因此,通过一些轻量级的 _**uid**_ 暴力破解,我发现 _**uid**=**1** 时检索到了一个用户名和密码:\
|
||||
`query={user(uid:1){user,password}}`
|
||||
@ -219,11 +219,11 @@ query = { hiddenFlags }
|
||||
|
||||
**查询字符串转储技巧(感谢 @BinaryShadow\_)**
|
||||
|
||||
如果你可以通过字符串类型进行搜索,例如:`query={theusers(description: ""){username,password}}`,并且你**搜索一个空字符串**,它将**转储所有数据**。 (_注意这个例子与教程的例子无关,对于这个例子假设你可以通过一个名为 "**description**" 的字符串字段使用 "**theusers**" 进行搜索_).
|
||||
如果你可以通过字符串类型进行搜索,例如:`query={theusers(description: ""){username,password}}`,并且你**搜索一个空字符串**,它将**转储所有数据**。 (_注意这个例子与教程的例子无关,对于这个例子假设你可以通过一个名为 "**description**" 的字符串字段使用 "**theusers**" 进行搜索_)。
|
||||
|
||||
### 搜索
|
||||
|
||||
在这个设置中,一个**数据库**包含**人员**和**电影**。**人员**通过他们的**电子邮件**和**姓名**进行识别;**电影**通过它们的**名称**和**评分**进行识别。**人员**可以互为朋友,也可以拥有电影,表示数据库中的关系。
|
||||
在这个设置中,一个**数据库**包含**人员**和**电影**。**人员**通过他们的**电子邮件**和**姓名**进行识别;**电影**通过它们的**名称**和**评分**进行识别。**人员**可以互为朋友,并且也有电影,表示数据库中的关系。
|
||||
|
||||
你可以通过**姓名**搜索人员并获取他们的电子邮件:
|
||||
```javascript
|
||||
@ -233,7 +233,7 @@ email
|
||||
}
|
||||
}
|
||||
```
|
||||
您可以通过姓名搜索人员并获取他们订阅的电影:
|
||||
您可以通过**姓名**搜索人员并获取他们**订阅**的**电影**:
|
||||
```javascript
|
||||
{
|
||||
searchPerson(name: "John Doe") {
|
||||
@ -258,7 +258,7 @@ name
|
||||
}
|
||||
}r
|
||||
```
|
||||
或者甚至是 **使用别名的多个不同对象的关系**:
|
||||
或者甚至**使用别名的多个不同对象的关系**:
|
||||
```javascript
|
||||
{
|
||||
johnsMovieList: searchPerson(name: "John Doe") {
|
||||
@ -285,13 +285,13 @@ name
|
||||
|
||||
**变更用于在服务器端进行更改。**
|
||||
|
||||
在**自省**中,您可以找到**声明的** **变更**。在下图中,"_MutationType_" 被称为 "_Mutation_",而 "_Mutation_" 对象包含变更的名称(在本例中为 "_addPerson_"):
|
||||
在 **introspection** 中可以找到 **声明的** **变更**。在下图中,"_MutationType_" 被称为 "_Mutation_",而 "_Mutation_" 对象包含变更的名称(在本例中为 "_addPerson_"):
|
||||
|
||||
.png>)
|
||||
|
||||
在此设置中,**数据库**包含**人员**和**电影**。**人员**通过其**电子邮件**和**姓名**进行识别;**电影**通过其**名称**和**评分**进行识别。**人员**可以互为朋友,并且也可以拥有电影,表示数据库中的关系。
|
||||
在此设置中,**数据库** 包含 **人员** 和 **电影**。**人员** 通过他们的 **电子邮件** 和 **姓名** 进行识别;**电影** 通过它们的 **名称** 和 **评分** 进行识别。**人员** 可以互为朋友,并且也可以拥有电影,表示数据库中的关系。
|
||||
|
||||
一个**在数据库中创建新**电影的变更可以如下所示(在此示例中,变更被称为 `addMovie`):
|
||||
一个 **在数据库中创建新** 电影的变更可以如下所示(在此示例中,变更被称为 `addMovie`):
|
||||
```javascript
|
||||
mutation {
|
||||
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
|
||||
@ -304,7 +304,7 @@ rating
|
||||
```
|
||||
**注意查询中如何指示值和数据类型。**
|
||||
|
||||
此外,数据库支持一个**mutation**操作,名为`addPerson`,允许创建**persons**及其与现有**friends**和**movies**的关联。重要的是要注意,朋友和电影必须在数据库中预先存在,然后才能将它们链接到新创建的人。
|
||||
此外,数据库支持一个 **mutation** 操作,名为 `addPerson`,允许创建 **persons** 及其与现有 **friends** 和 **movies** 的关联。重要的是要注意,朋友和电影必须在数据库中预先存在,然后才能将它们链接到新创建的人。
|
||||
```javascript
|
||||
mutation {
|
||||
addPerson(name: "James Yoe", email: "jy@example.com", friends: [{name: "John Doe"}, {email: "jd@example.com"}], subscribedMovies: [{name: "Rocky"}, {name: "Interstellar"}, {name: "Harry Potter and the Sorcerer's Stone"}]) {
|
||||
@ -353,7 +353,7 @@ releaseYear
|
||||
|
||||
越来越多的**graphql端点正在禁用自省**。然而,当收到意外请求时,graphql抛出的错误足以让像[**clairvoyance**](https://github.com/nikitastupin/clairvoyance)这样的工具重建大部分架构。
|
||||
|
||||
此外,Burp Suite扩展[**GraphQuail**](https://github.com/forcesunseen/graphquail)扩展**观察通过Burp的GraphQL API请求**,并**构建**一个内部GraphQL**架构**,每当它看到新的查询时。它还可以为GraphiQL和Voyager公开架构。当收到自省查询时,该扩展返回一个假响应。因此,GraphQuail显示了API中可用的所有查询、参数和字段。有关更多信息,[**请查看此处**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema)。
|
||||
此外,Burp Suite扩展[**GraphQuail**](https://github.com/forcesunseen/graphquail) **观察通过Burp的GraphQL API请求**并**构建**一个内部GraphQL **架构**,每当它看到新的查询时。它还可以为GraphiQL和Voyager公开架构。当收到自省查询时,该扩展返回一个假响应。因此,GraphQuail显示了API中可用的所有查询、参数和字段。有关更多信息,[**请查看此处**](https://blog.forcesunseen.com/graphql-security-testing-without-a-schema)。
|
||||
|
||||
一个很好的**词表**可以在这里发现[**GraphQL实体**](https://github.com/Escape-Technologies/graphql-wordlist?)。
|
||||
|
||||
@ -397,23 +397,23 @@ ws.send(JSON.stringify(graphqlMsg))
|
||||
```
|
||||
### **发现暴露的 GraphQL 结构**
|
||||
|
||||
当 introspection 被禁用时,检查网站源代码中 JavaScript 库中预加载的查询是一种有用的策略。这些查询可以通过开发者工具中的 `Sources` 选项卡找到,提供有关 API 架构的见解,并揭示潜在的 **暴露的敏感查询**。在开发者工具中搜索的命令是:
|
||||
当 introspection 被禁用时,检查网站源代码中 JavaScript 库中预加载的查询是一种有用的策略。这些查询可以通过开发者工具中的 `Sources` 选项卡找到,提供有关 API 架构的见解,并揭示潜在的 **暴露敏感查询**。在开发者工具中搜索的命令是:
|
||||
```javascript
|
||||
Inspect/Sources/"Search all files"
|
||||
file:* mutation
|
||||
file:* query
|
||||
```
|
||||
## CSRF in GraphQL
|
||||
## GraphQL中的CSRF
|
||||
|
||||
如果你不知道什么是 CSRF,请阅读以下页面:
|
||||
如果你不知道什么是CSRF,请阅读以下页面:
|
||||
|
||||
{{#ref}}
|
||||
../../pentesting-web/csrf-cross-site-request-forgery.md
|
||||
{{#endref}}
|
||||
|
||||
在外面,你将能够找到几个 **未配置 CSRF 令牌的** GraphQL 端点。
|
||||
在外面,你将能够找到几个**未配置CSRF令牌的**GraphQL端点。
|
||||
|
||||
请注意,GraphQL 请求通常通过使用 Content-Type **`application/json`** 的 POST 请求发送。
|
||||
请注意,GraphQL请求通常通过使用Content-Type **`application/json`**的POST请求发送。
|
||||
```javascript
|
||||
{"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
|
||||
```
|
||||
@ -459,7 +459,7 @@ query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
|
||||
|
||||
[将查询链接](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln)在一起可以绕过一个弱认证系统。
|
||||
|
||||
在下面的示例中,您可以看到操作是 "forgotPassword",并且它应该只执行与之关联的 forgotPassword 查询。通过在末尾添加一个查询可以绕过这一点,在这种情况下,我们添加 "register" 和一个用户变量,以便系统注册为新用户。
|
||||
在下面的示例中,您可以看到操作是“forgotPassword”,并且它应该只执行与之关联的 forgotPassword 查询。通过在末尾添加一个查询可以绕过这一点,在这种情况下,我们添加“register”和一个用户变量,以便系统注册为新用户。
|
||||
|
||||
<figure><img src="../../images/GraphQLAuthBypassMethod.PNG" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
@ -469,7 +469,7 @@ query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
|
||||
|
||||
要详细了解 GraphQL 别名,推荐以下资源:[Aliases](https://portswigger.net/web-security/graphql/what-is-graphql#aliases)。
|
||||
|
||||
虽然别名的主要目的是减少大量 API 调用的必要性,但已识别出一个意外的用例,其中别名可以被用来对 GraphQL 端点执行暴力攻击。这是可能的,因为某些端点受到速率限制器的保护,旨在通过限制**HTTP 请求的数量**来阻止暴力攻击。然而,这些速率限制器可能没有考虑到每个请求中的操作数量。鉴于别名允许在单个 HTTP 请求中包含多个查询,它们可以绕过此类速率限制措施。
|
||||
虽然别名的主要目的是减少大量 API 调用的必要性,但已识别出一个意外的用例,其中别名可以被利用来对 GraphQL 端点执行暴力攻击。这是可能的,因为某些端点受到速率限制器的保护,旨在通过限制**HTTP 请求的数量**来阻止暴力攻击。然而,这些速率限制器可能没有考虑到每个请求中的操作数量。鉴于别名允许在单个 HTTP 请求中包含多个查询,它们可以绕过此类速率限制措施。
|
||||
|
||||
考虑下面提供的示例,它说明了如何使用别名查询来验证商店折扣代码的有效性。这种方法可以绕过速率限制,因为它将多个查询编译成一个 HTTP 请求,可能允许同时验证多个折扣代码。
|
||||
```bash
|
||||
@ -490,7 +490,7 @@ valid
|
||||
|
||||
### Alias Overloading
|
||||
|
||||
**Alias Overloading** 是一种 GraphQL 漏洞,攻击者通过为同一字段重载查询,使用多个别名,导致后端解析器重复执行该字段。这可能会使服务器资源过载,从而导致 **Denial of Service (DoS)**。例如,在下面的查询中,同一字段 (`expensiveField`) 被请求了 1,000 次,使用别名,迫使后端计算 1,000 次,可能会耗尽 CPU 或内存:
|
||||
**Alias Overloading** 是一种 GraphQL 漏洞,攻击者通过为同一字段重载查询中的多个别名,导致后端解析器重复执行该字段。这可能会使服务器资源过载,从而导致 **Denial of Service (DoS)**。例如,在下面的查询中,同一字段 (`expensiveField`) 被请求了 1,000 次,使用别名强迫后端计算 1,000 次,可能会耗尽 CPU 或内存:
|
||||
```graphql
|
||||
# Test provided by https://github.com/dolevf/graphql-cop
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
@ -501,7 +501,7 @@ curl -X POST -H "Content-Type: application/json" \
|
||||
|
||||
### **基于数组的查询批处理**
|
||||
|
||||
**基于数组的查询批处理**是一种漏洞,其中GraphQL API允许在单个请求中批处理多个查询,使攻击者能够同时发送大量查询。这可能会通过并行执行所有批处理查询来压垮后端,消耗过多的资源(CPU、内存、数据库连接),并可能导致**服务拒绝(DoS)**。如果对批处理中的查询数量没有限制,攻击者可以利用这一点来降低服务可用性。
|
||||
**基于数组的查询批处理** 是一种漏洞,其中 GraphQL API 允许在单个请求中批处理多个查询,使攻击者能够同时发送大量查询。这可能会通过并行执行所有批处理查询来压垮后端,消耗过多的资源(CPU、内存、数据库连接),并可能导致 **服务拒绝(DoS)**。如果对批处理中的查询数量没有限制,攻击者可以利用这一点来降低服务可用性。
|
||||
```graphql
|
||||
# Test provided by https://github.com/dolevf/graphql-cop
|
||||
curl -X POST -H "User-Agent: graphql-cop/1.13" \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user