跳转至

Object Limit Overriding in GraphQL

GraphQL 中的对象限制覆盖

描述

GraphQL 中的对象限制覆盖(Object Limit Overriding)是指攻击者可以操纵查询参数以超过 API 预期限制的漏洞。这通常涉及将极大的值传递给分页或限制参数,从而可能导致拒绝服务(DoS)攻击或过度消耗资源。

潜在风险:

拒绝服务(DoS): 通过请求过多的对象,攻击者可以使服务器不堪重负,导致性能下降或中断。

资源耗尽: 请求大量对象的查询可能会使服务器的内存和处理能力超载。

数据暴露: 在某些情况下,绕过限制可能会导致未经授权访问大量数据。

成本增加: 对于基于云的服务,由于资源使用率高,处理具有极大限制的查询可能会导致意想不到的成本。

存在漏洞的查询示例:

query {
  users(first: 1000000) {
    id
    name
    email
  }
}

建议

为了缓解 GraphQL 中对象限制覆盖的风险,请实施以下措施:

查询复杂性分析: 使用工具或库来分析并限制传入查询的复杂性。诸如 graphql-query-complexity 之类的库可以提供帮助。

速率限制(Rate Limiting): 实施速率限制,以限制单个用户或 IP 地址在特定时间范围内可以发送的查询数量。

分页和限制: 对单个查询返回的数据量应用限制。确保使用分页来控制数据量。

Example Implementation:

const { ApolloServer, gql } = require('apollo-server');
const { getComplexity, simpleEstimator, fieldExtensionsEstimator } = require('graphql-query-complexity');
const { GraphQLObjectType, GraphQLInt, GraphQLString, GraphQLSchema } = require('graphql');

// Define your GraphQL schema
const typeDefs = gql`
  type Query {
    hello: String
    user(id: ID!): User
  }

  type User {
    id: ID!
    name: String
    age: Int
  }
`;

// Define your resolvers
const resolvers = {
  Query: {
    hello: () => 'Hello world!',
    user: (_, { id }) => ({
      id,
      name: 'John Doe',
      age: 30,
    }),
  },
};

// Create an Apollo Server instance with query complexity analysis
const server = new ApolloServer({
  typeDefs,
  resolvers,
  plugins: [
    {
      // This plugin computes the complexity of incoming queries
      requestDidStart: () => ({
        didResolveOperation({ request, document }) {
          const complexity = getComplexity({
            schema: server.schema,
            query: document,
            variables: request.variables,
            estimators: [
              fieldExtensionsEstimator(),
              simpleEstimator({ defaultComplexity: 1 }),
            ],
          });

          // Define a maximum complexity limit
          const maxComplexity = 100;

          // Check if the query complexity exceeds the maximum allowed
          if (complexity > maxComplexity) {
            throw new Error(`Query is too complex: ${complexity}. Maximum allowed complexity: ${maxComplexity}`);
          }
        },
      }),
    },
  ],
});

// Start the server
server.listen().then(({ url }) => {
  console.log(`🚀 Server ready at ${url}`);
});
from graphql import parse, execute, validate, GraphQLError
from graphql.language.visitor import visit, Visitor

class ComplexityVisitor(Visitor):
    def __init__(self):
        self.complexity = 0
        self.max_complexity = 100

    def enter_field(self, node, key, parent, path, ancestors):
        complexity = 1  # Base complexity for each field
        self.complexity += complexity
        if self.complexity > self.max_complexity:
            raise GraphQLError(f"Query complexity exceeds maximum allowed complexity of {self.max_complexity}")

def complexity_middleware(schema, query):
    document = parse(query)
    visitor = ComplexityVisitor()
    visit(document, visitor)
    return visitor.complexity

def execute_with_complexity_check(schema, query, variables=None):
    complexity = complexity_middleware(schema, query)
    if complexity > 100:
        raise GraphQLError(f"Query complexity exceeds maximum allowed complexity of 100")
    result = execute(schema, parse(query), variable_values=variables)
    return result

By using these recommendations and configurations, you can better protect your GraphQL APIs from the risks associated with object limit overriding.

链接

标准

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