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
- GraphQL Vulnerabilities and Common Attacks: What You Need to Know
- OWASP GraphQL Security Cheat Sheet
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