Saltar a contenido

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.

Detecte este problema con Ostorlab

Ostorlab busca este problema en aplicaciones web, API y redes.

Crear una cuenta

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
  • OWASP_TOP_10:
    • A03_2021