Saltar a contenido

Object Limit Overriding in GraphQL

Anulación del límite de objetos en GraphQL

Descripción

La anulación de límite de objetos (Object Limit Overriding) en GraphQL se refiere a una vulnerabilidad donde un atacante puede manipular los argumentos de la consulta para superar los límites previstos de una API. Esto a menudo implica pasar valores extremadamente grandes a los parámetros de paginación o límite, lo que puede provocar ataques de denegación de servicio (DoS) o un consumo excesivo de recursos.

Riesgos potenciales:

Denegación de servicio (DoS): Al solicitar un número excesivo de objetos, los atacantes pueden abrumar el servidor, causando degradación del rendimiento o interrupciones.

Agotamiento de recursos: Las consultas que solicitan una gran cantidad de objetos pueden sobrecargar la memoria y las capacidades de procesamiento del servidor.

Exposición de datos: En algunos casos, eludir los límites podría llevar al acceso no autorizado a grandes cantidades de datos.

Aumento de costos: Para los servicios basados en la nube, el procesamiento de consultas con límites extremadamente altos puede resultar en costos inesperados debido al alto uso de recursos.

Ejemplo de consulta vulnerable:

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

Recomendación

Para mitigar el riesgo de la anulación del límite de objetos en GraphQL, implemente las siguientes medidas:

Análisis de la complejidad de la consulta: Utilice herramientas o bibliotecas para analizar y limitar la complejidad de las consultas entrantes. Bibliotecas como graphql-query-complexity pueden ayudar.

Limitación de velocidad (Rate Limiting): Implemente la limitación de velocidad para restringir el número de consultas que puede enviar un solo usuario o dirección IP dentro de un período de tiempo determinado.

Paginación y límites: Aplique límites a la cantidad de datos devueltos en una sola consulta. Asegúrese de que se utilice la paginación para controlar el volumen de datos.

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.

Enlaces

Estándares

  • 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