GraphQL security is protection against injections, overflows, unauthorized queries and DDoS attacks.
System design context: GraphQL's flexibility is also its greatest security risk. Unlike REST where the server controls which data each endpoint returns, GraphQL lets clients request any combination of fields. An attacker can craft deeply nested queries that exhaust server resources, or request fields they should not have access to. Security must be layered at the server, client, and network levels.
1. Validation and limits on the server:
1import depthLimit from "graphql-depth-limit";2import { createComplexityRule } from "graphql-query-complexity";34const server = new ApolloServer({5 schema,6 validationRules: [7 depthLimit(10), // Max nesting depth8 createComplexityRule({9 maximumComplexity: 1000,10 estimators: [fieldExtensionsEstimator()],11 }),12 ],13});
2. Authorization at field level:
1const resolvers = {2 Query: {3 users: (_, __, context) => {4 if (!context.user) throw new AuthenticationError("Authorization required");5 if (!context.user.isAdmin) throw new ForbiddenError("Access denied");6 return db.users.findAll();7 },8 },9};
3. Injection protection (on client):
1// Bad: string concatenation2const query = gql`3 query GetUser($id: ID!) {4 user(id: $id) { name }5 }6`;7// Use Variables, not concatenation!8client.query({ query, variables: { id: userInput } });
4. Persisted Queries:
1query_hash: "abc123"2→ Server executes ONLY predefined queries3→ Attacker cannot send arbitrary query
5. CORS and Rate Limiting:
1// Limit number of requests2const rateLimiter = new RateLimiter({3 max: 100,4 window: 60 * 1000, // 100 requests per minute5});
Common pitfalls with root cause + fix:
1new ApolloServer({2 introspection: process.env.NODE_ENV !== "production",3});
Monitoring: