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>
|
||||
|
||||
@ -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,11 +285,11 @@ name
|
||||
|
||||
**变更用于在服务器端进行更改。**
|
||||
|
||||
在**自省**中,您可以找到**声明的** **变更**。在下图中,"_MutationType_" 被称为 "_Mutation_",而 "_Mutation_" 对象包含变更的名称(在本例中为 "_addPerson_"):
|
||||
在 **introspection** 中可以找到 **声明的** **变更**。在下图中,"_MutationType_" 被称为 "_Mutation_",而 "_Mutation_" 对象包含变更的名称(在本例中为 "_addPerson_"):
|
||||
|
||||
.png>)
|
||||
|
||||
在此设置中,**数据库**包含**人员**和**电影**。**人员**通过其**电子邮件**和**姓名**进行识别;**电影**通过其**名称**和**评分**进行识别。**人员**可以互为朋友,并且也可以拥有电影,表示数据库中的关系。
|
||||
在此设置中,**数据库** 包含 **人员** 和 **电影**。**人员** 通过他们的 **电子邮件** 和 **姓名** 进行识别;**电影** 通过它们的 **名称** 和 **评分** 进行识别。**人员** 可以互为朋友,并且也可以拥有电影,表示数据库中的关系。
|
||||
|
||||
一个 **在数据库中创建新** 电影的变更可以如下所示(在此示例中,变更被称为 `addMovie`):
|
||||
```javascript
|
||||
@ -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,13 +397,13 @@ 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,请阅读以下页面:
|
||||
|
||||
@ -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" \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user