Object Limit Overriding in GraphQL
Contournement de la limite d'objets dans GraphQL
Description
Le contournement de la limite d'objets dans GraphQL (Object Limit Overriding) fait référence à une vulnérabilité où un attaquant peut manipuler les arguments de requête pour dépasser les limites prévues d'une API. Cela implique souvent la transmission de valeurs extrêmement importantes aux paramètres de pagination ou de limite, ce qui peut entraîner des attaques par déni de service (DoS) ou une consommation excessive de ressources.
Risques potentiels :
Déni de service (DoS) : En demandant un nombre excessif d'objets, les attaquants peuvent submerger le serveur, provoquant une dégradation des performances ou des pannes.
Épuisement des ressources : Les requêtes demandant un grand nombre d'objets peuvent surcharger la mémoire et les capacités de traitement du serveur.
Exposition des données : Dans certains cas, le contournement des limites peut conduire à un accès non autorisé à de grandes quantités de données.
Augmentation des coûts : Pour les services basés sur le cloud, le traitement de requêtes avec des limites extrêmement élevées peut entraîner des coûts inattendus en raison d'une utilisation importante des ressources.
Exemple de requête vulnérable :
query {
users(first: 1000000) {
id
name
email
}
}
Recommandation
Pour atténuer le risque de contournement de la limite d'objets dans GraphQL, mettez en œuvre les mesures suivantes :
Analyse de la complexité des requêtes : Utilisez des outils ou des bibliothèques pour analyser et limiter la complexité des requêtes entrantes. Des bibliothèques comme graphql-query-complexity peuvent être utiles.
Limitation de débit (Rate Limiting) : Mettez en œuvre une limitation de débit pour restreindre le nombre de requêtes pouvant être envoyées par un seul utilisateur ou une seule adresse IP dans un certain laps de temps.
Pagination et limites : Appliquez des limites à la quantité de données renvoyées dans une seule requête. Assurez-vous que la pagination est utilisée pour contrôler le volume de données.
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.
Liens
- GraphQL Vulnerabilities and Common Attacks: What You Need to Know
- OWASP GraphQL Security Cheat Sheet
Normes
- 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