GraphQL Security

GraphQL oferece flexibilidade poderosa mas introduz vetores de ataque únicos: query complexity attacks, introspection abuse, authorization bypass e information disclosure.

Vulnerabilidades Comuns em GraphQL

1. Query Depth / Complexity Attacks

Queries deeply nested podem causar DoS consumindo recursos excessivos:

      query MaliciousQuery {
      user(id: "1") {
      posts {
      comments {
      author {
      posts {
      comments {
      author {
      posts {
      # ... infinitamente nested
      }
      }
      }
      }
      }
      }
      }
      }
      }
      

2. Introspection Abuse

Introspection habilitado em produção revela schema completo, facilitando reconnaissance:

      query IntrospectionQuery {
      __schema {
      types {
      name
      fields {
      name
      type {
      name
      }
      }
      }
      }
      }
      

3. Broken Authorization

Autorização deve ocorrer em resolvers, não apenas em queries top-level. IDOR comum quando authorization não é checked em nested fields.

4. Injection Attacks

GraphQL não imune a SQLi, NoSQLi se inputs não são sanitizados nos resolvers.

Proteções Essenciais

Query Depth Limiting

      // Apollo Server example
      import depthLimit from 'graphql-depth-limit';
      const server = new ApolloServer({
      typeDefs,
      resolvers,
      validationRules: [depthLimit(5)]  // Max depth 5
      });
      

Query Complexity Analysis

      import { createComplexityLimitRule } from 'graphql-validation-complexity';
      const server = new ApolloServer({
      validationRules: [
      createComplexityLimitRule(1000, {
      scalarCost: 1,
      objectCost: 5,
      listFactor: 10
      })
      ]
      });
      

Rate Limiting

  • Query-based: Limitar queries por minuto por usuário
  • Complexity-based: Budget de complexity points
  • Cost analysis: Atribuir custo a cada field

Autorização em GraphQL

Field-Level Authorization

      const resolvers = {
      Query: {
      user: async (parent, { id }, context) => {
      // Autorização em query level
      if (!context.user) {
      throw new AuthenticationError('Not authenticated');
      }
      return getUserById(id);
      }
      },
      User: {
      email: (user, args, context) => {
      // Autorização em field level
      if (context.user.id !== user.id && !context.user.isAdmin) {
      return null;  // Ocultar email de outros usuários
      }
      return user.email;
      },
      ssn: (user, args, context) => {
      // Field extremamente sensível
      if (!context.user.isAdmin) {
      throw new ForbiddenError('Admin only');
      }
      return user.ssn;
      }
      }
      };
      

Directive-Based Authorization

      type User @auth(requires: AUTHENTICATED) {
      id: ID!
      username: String!
      email: String! @auth(requires: OWNER_OR_ADMIN)
      ssn: String! @auth(requires: ADMIN)
      }
      

Proteção de Introspection

      const server = new ApolloServer({
      typeDefs,
      resolvers,
      introspection: process.env.NODE_ENV !== 'production',
      // Ou controlar por role
      plugins: [{
      requestDidStart() {
      return {
      didResolveOperation({ request, context }) {
      if (request.operationName === 'IntrospectionQuery'
      && !context.user?.isAdmin) {
      throw new ForbiddenError('Introspection disabled');
      }
      }
      }
      }
      }]
      });
      

Input Validation

  • Schema validation: GraphQL valida types automaticamente
  • Custom scalars: Email, URL, DateTime com validation
  • Input sanitization: Sanitizar inputs antes de usar em resolvers
  • Parameterized queries: Usar prepared statements em database

Batching e DataLoader

Prevenir N+1 problem que pode ser explorado para DoS:

      import DataLoader from 'dataloader';
      const userLoader = new DataLoader(async (userIds) => {
      const users = await getUsersByIds(userIds);
      return userIds.map(id => users.find(u => u.id === id));
      });
      const resolvers = {
      Post: {
      author: (post, args, { userLoader }) => {
      return userLoader.load(post.authorId);  // Batched!
      }
      }
      };
      

Monitoring e Logging

  • Query logging: Log todas queries com metadata (user, IP, time)
  • Error tracking: Sentry, Datadog para exceptions
  • Performance monitoring: Apollo Studio, GraphQL Hive
  • Anomaly detection: Alertar em queries suspeitas (muito complexas, etc.)

Ferramentas de Segurança

  • GraphQL Armor: Security middleware suite
  • graphql-shield: Permissions layer com rules
  • InQL: Burp Suite extension para GraphQL pentest
  • BatchQL: Security testing tool para GraphQL
  • graphql-cop: Security auditing tool

OWASP GraphQL Top 10

  1. Broken Object Level Authorization
  2. Broken Authentication
  3. Excessive Data Exposure
  4. Resource Exhaustion
  5. Broken Function Level Authorization
  6. Mass Assignment
  7. Security Misconfiguration
  8. Injection
  9. Improper Assets Management
  10. Insufficient Logging & Monitoring

Práticas de Desenvolvimento Seguro

  • Implementar autorização em TODOS os resolvers
  • Desabilitar introspection em produção
  • Limitar query depth e complexity
  • Rate limiting agressivo
  • Usar DataLoader para prevenir N+1
  • Sanitizar inputs antes de processing
  • Implementar comprehensive logging
  • Regular security audits e pentests

Recomendações Finais

GraphQL exige mudança de mindset de segurança comparado a REST. Flexibilidade do client requer defesas robustas no server. Implemente depth limiting, complexity analysis e field-level authorization desde o início. Use ferramentas de monitoring para detectar abuse patterns. Teste regularmente com ferramentas especializadas como InQL e BatchQL.