某不知名博客 某不知名博客
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Carsaid

安全界的小学生
首页
  • 《vulcat文档》
  • Web安全

    • 《BurpSuite及官方实验室》
    • 《OSWE学习历程》
  • 云原生安全

    • 《Docker命令大全》
    • 《CKS考试学习指南》
    • 《旧-Kubernetes教程》
漏洞库
  • 《渗透工具大全》
  • 《云安全》
事件库
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前言

  • 服务器端主题(翻译)

  • 客户端主题(翻译)

  • 高级主题(翻译)

    • 高级主题
    • 不安全的反序列化

    • Web LLM攻击

    • GraphQL API漏洞

      • GraphQL API漏洞
      • 什么是GraphQL
        • 什么是GraphQL?
        • GraphQL的工作原理
        • 什么是GraphQL模式?
        • 什么是GraphQL查询?
        • 什么是GraphQL变更?
        • 查询和变更的组成部分
          • 字段
          • 参数
          • 变量
          • 别名
          • 片段
        • 订阅
        • 内省
    • 服务端模板注入

    • Web缓存投毒

    • HTTP主机头攻击

    • HTTP请求走私

    • OAuth身份验证漏洞

    • JWT攻击

    • 原型链污染

    • 基本技能

  • 扩展阅读(翻译)

  • 个人学习笔记

  • 实验室做题记录

  • BurpSuite及官方实验室
  • 高级主题(翻译)
  • GraphQL API漏洞
carsaid
2023-11-07
目录

什么是GraphQL

翻译

原文:https://portswigger.net/web-security/graphql/what-is-graphql

- name: 翻译
  desc: 原文:https://portswigger.net/web-security/graphql/what-is-graphql
  bgColor: '#F0DFB1'
  textColor: 'green'
1
2
3
4

# 1什么是GraphQL?

GraphQL 是一种 API 查询语言,旨在促进客户端和服务器之间的高效通信。它使用户能够 在响应中准确指定 他们想要的那部分数据,有时在使用 REST API 时,这有助于避免出现大型响应对象和重复调用。

GraphQL 服务定义了一个协议,客户端可以通过该协议 与服务器进行通信。客户端不需要知道数据所在的位置。相反,客户端将查询发送到 GraphQL 服务器,该服务器从相关位置获取数据。由于 GraphQL 与平台无关,因此它可以使用多种编程语言实现,并且可以与几乎任何数据存储进行通信。

笔记

本页讲述了 GraphQL 是什么以及它是如何工作的。有关如何测试 GraphQL 漏洞的具体信息,请参阅GraphQL API漏洞 (opens new window)。

# 2GraphQL的工作原理

GraphQL 模式定义了服务数据的结构,可以列出可用的对象(也称为类型)、字段和关系。

根据 GraphQL 模式所描述的数据,可以使用三种类型的操作进行数据处理:

  • 查询并提取数据。
  • 变更可以被添加、更改或删除的数据。
  • 订阅类似于查询,但它设置了一个持久性连接,服务器通过该连接,可以将指定格式的数据 主动推送到客户端。

所有 GraphQL 操作都使用相同的端点,并且通常作为 POST 请求发送。这与 REST API 有很大的不同,后者在一系列 HTTP 方法中使用特定于操作的端点。对于 GraphQL,操作的类型和名称定义了查询的处理方式,而不是将查询发送到指定的端点 或 使用不同的 HTTP 方法。

(((译者加:REST API 定义了多个端点,不同的操作需要使用不同的 HTTP 方法并请求不同的端点。而 GraphQL 只定义一个端点,所有的操作都使用同一个端点,GraphQL 会根据你发送的 类型/名称 来判断你具体要做哪些操作)))

GraphQL 服务通常会使用请求结构中的 JSON 对象来响应操作。

# 3什么是GraphQL模式?

在 GraphQL 中,模式(schema)用于表示服务器前端和后端之间的协议。它使用人类可读的语言来定义模式,并将可用的数据定义为一系列类型。然后,这些类型可以由服务实现。

定义的大多数类型都是对象类型,它定义了可用的对象以及它们所具有的字段和参数。每个字段都有自己的类型,可以是另一个对象,也可以是标量、枚举、联合、接口或自定义类型。

下面的示例展示了 Product 类型的简单模式定义。运算符!表示该字段在调用时不可为空(必填项)。

    #Example schema definition

    type Product {
        id: ID!
        name: String!
        description: String!
        price: Int
    }
1
2
3
4
5
6
7
8

模式中还必须包含至少一个可用查询。通常,它们还包含可用于变更的详细信息。

# 4什么是GraphQL查询?

GraphQL 查询从数据存储中检索数据。它们大致等同于 REST API 中的 GET 请求。

一般来说,查询通常由以下几个关键部分组成:

  • query操作类型。这在理论上来说是可选的,但推荐你将其加上,明确地告诉服务器 传入的请求是一个查询。
  • 查询名称。这可以是你想要的任何东西。查询名称也是可选的,但建议加上,因为它有助于调试。
  • 数据结构。这是查询应返回的数据。
  • (可选)一个或多个参数。这些参数用于创建查询 并 返回特定对象的详细信息(例如,“为我提供 ID 为 123 的产品名称和描述”)。

下面的示例展示了一个名为myGetProductQuery的查询,该查询请求id为123的产品名称和描述字段。

    #Example query

    query myGetProductQuery {
        getProduct(id: 123) {
            name
            description
        }
    }
1
2
3
4
5
6
7
8

请注意,产品类型在模式中包含的字段,可能比此处请求的字段多。仅请求所需数据的能力是 GraphQL 灵活性的重要组成部分。

(((译者加:Product类型可能不止name和description这两个字段,即使有成百上千个字段,你也可以通过 GraphQL 获取你所需要的部分数据,而不用一下子全部获取)))

# 5什么是GraphQL变更?

变更以某种方式改变数据,包括添加、删除或编辑数据。它们大致等同于 REST API 的 POST、PUT 和 DELETE 方法。

与查询一样,变更也具有一个操作类型、名称和返回的数据结构。然而,变更总是接受某种类型的输入。这可以是一个内联值,但实际上通常作为变量提供。

下面的示例展示了创建新产品的变更及其相关响应。在这种情况下,服务被配置为自动为新产品分配一个 ID,该 ID 已按请求返回。

    #示例变更请求

    mutation {
        createProduct(name: "Flamin' Cocktail Glasses", listed: "yes") {
            id
            name
            listed
        }
    }

1
2
3
4
5
6
7
8
9
10
    #示例变更响应

    {
        "data": {
            "createProduct": {
                "id": 123,
                "name": "Flamin' Cocktail Glasses",
                "listed": "yes"
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11

# 6查询和变更的组成部分

GraphQL 语法包含几个用于 查询和变更 的常见组件。

# 6.1字段

所有 GraphQL 类型都包含可查询的数据项,称为字段。当你发送一个查询或变更时,你可以指定希望 API 返回哪些字段。响应将反映请求中指定的内容。

下面的示例展示了一个查询,用于获取所有员工的 ID 和姓名详细信息及其关联的响应。在本例中,id、name.firstname和name.lastname是请求的字段。

    #请求

    query myGetEmployeeQuery {
        getEmployees {
            id
            name {
                firstname
                lastname
            }
        }
    }

1
2
3
4
5
6
7
8
9
10
11
12
    #响应

    {
        "data": {
            "getEmployees": [
                {
                    "id": 1,
                    "name" {
                        "firstname": "Carlos",
                        "lastname": "Montoya"
                    }
                },
                {
                    "id": 2,
                    "name" {
                        "firstname": "Peter",
                        "lastname": "Wiener"
                    }
                }
            ]
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 6.2参数

参数是为特定字段提供的值。可以在模式中定义 可供接受的参数类型。

当你发送包含参数的查询或变更时,GraphQL 服务器会根据其配置来确定如何响应。例如,它可能会返回一个特定对象,而不是所有对象的详细信息。

下面的示例展示了一个getEmployee请求,该请求将员工 ID 作为参数。在这种情况下,服务器只响应与该 ID 匹配的员工详细信息。

    #带参数的示例查询

    query myGetEmployeeQuery {
        getEmployees(id:1) {
            name {
                firstname
                lastname
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
    #对查询的响应

    {
        "data": {
            "getEmployees": [
            {
                "name" {
                    "firstname": Carlos,
                    "lastname": Montoya
                    }
                }
            ]
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

笔记

如果使用用户提供的参数直接访问对象,则 GraphQL API 可能容易受到访问控制 (opens new window)漏洞的影响,例如不安全的直接对象引用(IDOR) (opens new window)。

# 6.3变量

变量使你能够传递动态参数,而不是直接在查询本身中使用参数。

基于变量的查询 与 使用内联参数的查询,具有相同的结构,但查询的某些方面单独取自基于 JSON 的变量字典。它们使你能够在多个查询中复用公共结构,只有变量本身的值会发生变化。

在构建使用变量的查询或变更时,你需要:

  • 声明变量和类型。
  • 在查询中的适当位置添加变量名称。
  • 从变量字典中传递变量键和值。

下面的示例展示了 与上一个示例中 相同的查询,但这次 ID 作为变量传递,而不是作为查询字符串的直接部分传递。

    #带变量的示例查询

    query getEmployeeWithVariable($id: ID!) {
        getEmployees(id:$id) {
            name {
                firstname
                lastname
            }
         }
    }

    Variables:
    {
        "id": 1
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

在此示例中,变量在第一行中声明为$id: ID!。字符!表示这是此查询的必填字段。然后,它在第二行中被作为参数使用id:$id。最后,在变量 JSON 字典中设置变量本身的值。有关如何测试这些漏洞的信息,请参阅 GraphQL API漏洞 (opens new window)。

# 6.4别名

GraphQL 对象不能包含多个同名属性。例如,以下查询无效,因为它尝试返回两个产品类型。

    #无效的查询

    query getProductDetails {
        getProduct(id: 1) {
            id
            name
        }
        getProduct(id: 2) {
            id
            name
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12

你可以使用别名来显式命名你希望 API 返回的属性,从而规避以上限制。通过别名,你可以在一个请求中 返回同一对象类型的多个实例。这有助于减少所需 API 的调用次数。

在下面的示例中,查询使用别名 为这两个产品分别指定了唯一名称。现在这个查询通过了验证,并返回详细信息。

    #使用别名的有效查询

    query getProductDetails {
        product1: getProduct(id: "1") {
            id
            name
        }
        product2: getProduct(id: "2") {
            id
            name
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
    #对查询的响应

    {
        "data": {
            "product1": {
                "id": 1,
                "name": "Juice Extractor"
             },
            "product2": {
                "id": 2,
                "name": "Fruit Overlays"
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14

笔记

有效地使用具有变更的别名,使你能够在一个 HTTP 请求中发送多个 GraphQL 消息。

有关如何使用此技术,绕过某些速率限制控制的详细信息,请参阅使用别名绕过速率限制 (opens new window)。

# 6.5片段

片段是查询或变更的可重用部分。它们包含属于关联类型的字段子集。

定义后,它们就可以被包含在查询或变更中。如果它们随后被修改,则修改后的值 将被包含在调用片段的每个查询或变更中。

下面的示例展示了一个getProduct查询,其中产品的详细信息包含在productInfo片段中。

    #片段示例

    fragment productInfo on Product {
        id
        name
        listed
    }
1
2
3
4
5
6
7
    #调用片段的查询

    query {
        getProduct(id: 1) {
            ...productInfo
            stock
        }
    }
1
2
3
4
5
6
7
8
    #包含片段中所定义字段的响应

    {
        "data": {
            "getProduct": {
                "id": 1,
                "name": "Juice Extractor",
                "listed": "no",
                "stock": 5
            }
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12

# 7订阅

订阅是一种特殊类型的查询。它使客户端能够与服务器建立长期连接,这样服务器就可以向客户端推送实时更新,而不需要一直轮询数据。订阅主要用于对大型对象的微小更改,以及需要小型实时更新的功能(如聊天系统或协作编辑)。

与常规查询和变更一样,订阅请求定义了要返回的数据结构。

订阅通常使用 WebSocket (opens new window) 实现。

# 8内省

“内省” 是一个内置的 GraphQL 函数,可用于查询服务器以获取有关模式的信息。它通常被用于 GraphQL IDE 和文档生成工具等应用程序。

与常规查询一样,你可以指定要返回的响应字段和结构。例如,你可能希望响应仅包含可用于变更的名称。

内省可能具有严重的信息泄露 (opens new window)风险,因为它可用于访问潜在的敏感信息(例如字段描述)并帮助攻击者了解如何与 API 交互。“在生产环境中禁用内省” 是最佳实践。

笔记

有关如何使用 GraphQL 内省查询和测试内省漏洞的更多信息,请参阅 GraphQL API漏洞 (opens new window)。

编辑 (opens new window)
GraphQL API漏洞
服务端模板注入

← GraphQL API漏洞 服务端模板注入→

最近更新
01
API测试笔记
04-30
02
msfvenom
03-29
03
Metasploit
03-29
更多文章>
Theme by Vdoing | Copyright © 2023-2024 Carsaid | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式