跳转至

Circular Fragment in GraphQL

GraphQL 中的循环片段

描述

GraphQL 中的循环片段(Circular fragments)是指 GraphQL 查询中的片段相互引用,从而导致循环引用的情况。这可能会引发无限循环、资源耗尽和拒绝服务(DoS)攻击等问题。攻击者可以利用这一点使 GraphQL 服务器不堪重负,使其对合法用户不可用或响应缓慢。

GraphQL 中循环片段的安全影响:

1. 拒绝服务(DoS): 循环片段引用可能导致服务器无休止地解析查询,消耗过多资源并最终导致崩溃或速度变慢。 2. 资源耗尽: 无限的片段循环可能导致高 CPU 和内存使用率,引起资源耗尽,从而降低应用程序或服务器的性能。 3. 查询复杂性漏洞利用: 攻击者可以利用循环片段构造复杂的查询,以利用 GraphQL 服务器中缺乏深度或递归限制的弱点。

循环片段的一个基本示例如下所示:

fragment UserFields on User {
  name
  ...MoreUserFields
}

fragment MoreUserFields on User {
  email
  ...UserFields
}

在此示例中,UserFields 引用了 MoreUserFields,并且 MoreUserFields 引用了 UserFields,从而创建了一个循环引用。

建议

为了缓解 GraphQL 中循环片段的风险,请考虑以下步骤:

1. 通过模式分析检测循环片段

对您的 GraphQL 模式(schema)和查询实施静态分析,以在循环引用被利用之前对其进行检测和阻止。一些 GraphQL 服务器库提供了用于分析模式的工具。

  • Tooling: 使用 GraphQL linting 工具(如 GraphQL Code Generator 或 GraphQL Inspector)来检测循环片段并防止它们进入生产环境。

使用 GraphQL Code Generator 的示例:

npm install @graphql-codegen/cli
npx graphql-codegen init

您可以配置代码生成器输出模式验证,以检测 GraphQL 查询中潜在的循环片段问题。

2. 实施查询成本分析

使用查询复杂性分析为每个字段、片段或查询分配“成本”。当查询或片段超过预定义的成本阈值时,可以自动拒绝它。

  • Tooling: 您可以使用 graphql-query-complexity 等库来计算查询成本并限制循环片段的影响。

使用 graphql-query-complexity 的 JavaScript 示例:

const { getComplexity, simpleEstimator } = require('graphql-query-complexity');

const server = new ApolloServer({
  schema,
  validationRules: [
    queryComplexity({
      estimators: [
        simpleEstimator({ defaultComplexity: 1 })
      ],
      maximumComplexity: 1000,  // Queries that exceed this complexity will be rejected
      onComplete: (complexity) => {
        console.log('Query Complexity:', complexity);
      },
    }),
  ],
});

3. 强制执行深度和递归限制

一些 GraphQL 服务器实现允许您定义查询深度和递归的限制以防止资源耗尽。这有助于避免由循环片段引起的无限循环。

  • Tooling: 例如,Apollo Server 支持查询深度限制,这可以防止过度的递归。

在 Apollo Server 中使用查询深度限制的示例:

const { ApolloServer } = require('apollo-server');
const depthLimit = require('graphql-depth-limit');

const server = new ApolloServer({
  schema,
  validationRules: [depthLimit(5)],  // Set query depth limit to 5
});

4. 明智地使用片段

避免在复杂查询中过度使用片段。过度使用可能会导致性能下降,并增加了循环引用的可能性。相反,应考虑将复杂的查询拆分为多个较小的查询。

  • Recommendation: 审查查询设计,并将片段的使用限制在特定的模块化数据块上。

示例:

query {
  user(id: "1") {
    name
    email
    posts {
      title
      content
    }
  }
}

与其将多个片段相互嵌套,不如使用像这样的简单查询。

链接

标准

  • CWE_TOP_25:
    • CWE_400
  • PCI_STANDARDS:
    • REQ_6_2
    • REQ_6_4
    • REQ_11_3
  • OWASP_MASVS_L2:
    • MSTG_PLATFORM_2
  • OWASP_ASVS_L3:
    • V13_4_1
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5
    • CC_9_1
  • HIPAA_CONTROLS:
    • SECURITY212
    • SECURITY213