Por que GraphQL Requer Atenção Especial

GraphQL revolucionou o desenvolvimento de APIs ao permitir que clientes solicitem exatamente os dados necessários em uma única requisição. Porém, essa flexibilidade introduz vetores de ataque únicos que não existem em APIs REST tradicionais.

68%
das APIs GraphQL em produção tem pelo menos uma vulnerabilidade crítica (Salt Security, 2025)

Enquanto REST tem endpoints fixos com respostas predefinidas, GraphQL expõe um schema flexível onde o cliente controla a estrutura da query. Isso inverte o modelo de segurança tradicional e exige controles específicos.

Diferenças de segurança REST vs GraphQL

  • REST: Endpoints fixos, fácil aplicar rate limiting por rota, WAF tradicional funciona bem
  • GraphQL: Único endpoint, queries dinâmicas, WAF tradicional não entende o payload
  • REST: Over-fetching e under-fetching controlados pelo servidor
  • GraphQL: Cliente define a query, pode solicitar grafos profundos e complexos
  • REST: Autorização por endpoint e método HTTP
  • GraphQL: Autorização deve ser por campo e tipo no schema

Vulnerabilidades Específicas de GraphQL

O OWASP API Security Top 10 cobre vulnerabilidades gerais de API, mas GraphQL tem vetores adicionais que merecem atenção específica:

Categorias de vulnerabilidades

  • Information Disclosure: Introspection, error messages verbosos, field suggestions
  • Denial of Service: Deep queries, circular fragments, batching abuse
  • Broken Authorization: IDOR em mutations, field-level permissions faltando
  • Injection: SQL injection via argumentos, NoSQL injection
  • Authentication Bypass: Mutations sensíveis sem autenticação

Ataques de Introspection

Introspection é um recurso do GraphQL que permite consultar o schema da API programaticamente. É extremamente útil em desenvolvimento, mas em produção expõe toda a superfície de ataque.

Ataque: Schema Enumeration

Atacante usa introspection para descobrir todos os tipos, campos, mutations e queries disponíveis.

# Query de introspection padrão
{
  __schema {
    types {
      name
      fields {
        name
        type { name }
      }
    }
    mutationType {
      fields { name }
    }
  }
}

Com o schema completo, o atacante identifica:

  • Campos sensíveis (ssn, creditCard, password, internalId)
  • Mutations administrativas (deleteUser, changeRole, resetPassword)
  • Relacionamentos entre tipos para escalar acesso
  • Campos deprecated que podem ter menos proteção

Proteção: Desabilitar Introspection em Produção

// Apollo Server
const server = new ApolloServer({
  typeDefs,
  resolvers,
  introspection: process.env.NODE_ENV !== 'production'
});

Query Batching e Brute Force

GraphQL permite enviar múltiplas queries ou mutations em uma única requisição HTTP. Isso pode ser abusado para bypass de rate limiting e ataques de brute force.

Ataque: Authentication Brute Force via Batching

Em vez de 1000 requisições HTTP, atacante envia 1 requisição com 1000 mutations de login.

# Uma requisição HTTP, 1000 tentativas de login
[
  {"query": "mutation { login(user:\"admin\", pass:\"123456\") { token }}"},
  {"query": "mutation { login(user:\"admin\", pass:\"password\") { token }}"},
  {"query": "mutation { login(user:\"admin\", pass:\"admin123\") { token }}"},
  // ... mais 997 tentativas
]

Alias Batching

Mesmo sem array batching, aliases permitem executar a mesma operação múltiplas vezes:

# Brute force com aliases em uma query
query {
  attempt1: login(user: "admin", pass: "123456") { token }
  attempt2: login(user: "admin", pass: "password") { token }
  attempt3: login(user: "admin", pass: "admin123") { token }
  # ...
}

Proteção contra Batching

  • Limitar número de queries por requisição batch
  • Limitar número de aliases por query
  • Rate limiting por operação, não por requisição HTTP
  • Detectar e bloquear padrões de batching suspeitos

DoS por Query Complexity

A flexibilidade de GraphQL permite construir queries extremamente profundas ou circulares que consomem recursos massivos do servidor.

Ataque: Deep Query DoS

Query que explora relacionamentos para criar carga exponencial.

query DeepDoS {
  users {
    posts {
      comments {
        author {
          posts {
            comments {
              author {
                posts { # contínua...
                }
              }
            }
          }
        }
      }
    }
  }
}

Query Cost Analysis

A solução é calcular o "custo" de cada query antes de executá-la e rejeitar queries que excedam um limite.

// Exemplo de cálculo de custo
const costMap = {
  User: 1,
  Post: 2,
  Comment: 1,
  posts: { multiplier: 10 }, // assume 10 posts por user
  comments: { multiplier: 20 } // assume 20 comments por post
};

// Query acima: 1 * 10 * 20 * 1 * 10 * 20 * ... = REJEITADA

Controles de Complexidade

  • Max depth: Limitar profundidade máxima da query (ex: 7 níveis)
  • Query cost: Calcular custo total e limitar (ex: 1000 pontos)
  • Timeout: Abortar queries que excedem tempo limite
  • Pagination obrigatória: Forçar limit/offset em listas

Falhas de Authorization

Em REST, autorização é tipicamente por endpoint. Em GraphQL, deve ser implementada no nível de campo e resolver, o que é frequentemente esquecido.

Ataque: IDOR via GraphQL

Usuario comum acessa dados de outros usuários através de IDs previsíveis.

# Usuario logado com ID 123 acessa dados do usuario 456
query {
  user(id: "456") {
    email
    ssn
    creditCards {
      number
      cvv
    }
  }
}

Field-Level Authorization

Cada campo sensível deve verificar permissões no resolver:

const resolvers = {
  User: {
    ssn: (parent, args, context) => {
      // Apenas o próprio usuário ou admin
      if (context.user.id !== parent.id && !context.user.isAdmin) {
        throw new ForbiddenError('Not authorized');
      }
      return parent.ssn;
    }
  }
};

Erro comum: Autorização apenas no Query Root

Verificar autorização apenas no resolver principal não é suficiente. Atacantes podem acessar dados sensíveis através de relacionamentos:

# Bypass: acessar SSN via relacionamento
query {
  posts(userId: "456") { # publico
    author {
      ssn # deveria ser protegido!
    }
  }
}

Injection Attacks

Argumentos de queries GraphQL podem ser vetores de injection se não forem tratados adequadamente nos resolvers.

Ataque: SQL Injection via GraphQL

query {
  users(filter: "name = 'admin' OR 1=1--") {
    id
    email
    password_hash # expoe todos os usuários
  }
}

GraphQL não previne injection automaticamente. Resolvers que constroem queries dinâmicas são vulneráveis.

Proteção contra Injection

  • Usar parametrização/prepared statements em todos os resolvers
  • Validar e sanitizar inputs com schema validation
  • Usar ORMs que escapam inputs automaticamente
  • Implementar allowlist de campos ordenáveis/filtráveis

Melhores Práticas de Proteção

1. Configuração segura do servidor

// Apollo Server com configuração segura
const server = new ApolloServer({
  typeDefs,
  resolvers,
  introspection: false, // desabilitar em produção
  playground: false, // desabilitar playground
  debug: false, // não expor stack traces
  validationRules: [
    depthLimit(7), // max depth
    costLimit({ maxCost: 1000 })
  ],
  formatError: (err) => ({
    message: err.message // não expor detalhes internos
  })
});

2. Checklist de segurança GraphQL

  • Introspection: Desabilitado em produção
  • Field suggestions: Desabilitado (expõe nomes de campos)
  • Query depth: Limitado (max 7-10 níveis)
  • Query cost: Calculado e limitado
  • Batching: Limitado ou desabilitado
  • Timeout: Configurado para queries
  • Rate limiting: Por operação, não por requisição
  • Authentication: Verificada antes de resolver queries
  • Authorization: Implementada por campo
  • Input validation: Em todos os argumentos
  • Error handling: Mensagens genéricas, sem stack traces
  • Logging: Queries, mutations e erros auditados

3. Persisted Queries

Em vez de aceitar queries arbitrárias, aceite apenas queries pré-registradas identificadas por hash.

// Cliente envia hash em vez da query completa
POST /graphql
{
  "extensions": {
    "persistedQuery": {
      "sha256Hash": "abc123..."
    }
  }
}

// Servidor executa query correspondente ao hash

Isso elimina inteiramente ataques de DoS por query complexity e injection, pois queries maliciosas nunca seriam registradas.

Ferramentas de Segurança para GraphQL

Análise estática e teste

  • GraphQL Cop: Auditoria automatizada de endpoints GraphQL
  • InQL (Burp Extension): Scanner GraphQL para pentest
  • graphql-shield: Middleware de permissões para Node.js
  • graphql-armor: Plugin de segurança com múltiplas proteções

WAF e API Gateway

  • AWS AppSync: GraphQL gerenciado com controles nativos
  • Apollo Router: Gateway com rate limiting e cost analysis
  • Inigo: GraphQL-native security e observability

Perguntas Frequentes

WAF tradicional protege GraphQL?

Parcialmente. WAFs tradicionais podem detectar payloads maliciosos genéricos (SQLi, XSS) nos argumentos, mas não entendem a semântica GraphQL. Ataques como deep queries, batching abuse e introspection passam despercebidos. Use WAF GraphQL-aware ou controles no servidor.

Como fazer rate limiting efetivo em GraphQL?

Rate limiting tradicional por IP/requisição não funciona bem devido ao batching. Implemente: (1) limite por operação executada, (2) limite por custo total de query, (3) limite por usuário autenticado, (4) limite de queries batch por requisição.

Persisted queries eliminam todos os riscos?

Persisted queries eliminam ataques de DoS por query complexity e injection de queries maliciosas. Porém, vulnerabilidades de autorização (IDOR), injection em argumentos e outros problemas de lógica de negócio permanecem. É uma camada importante, mas não suficiente sozinha.

Conclusão

APIs GraphQL oferecem flexibilidade poderosa, mas essa flexibilidade vem com responsabilidade de segurança aumentada. A superfície de ataque é diferente de REST, e controles tradicionais não são suficientes.

Priorize: desabilitar introspection em produção, implementar query cost analysis, autorização field-level, e considerar persisted queries para ambientes de alta segurança. Teste suas APIs GraphQL com ferramentas específicas como GraphQL Cop e InQL.

A segurança de GraphQL é uma área em evolução. Mantenha-se atualizado com as recomendações do OWASP e considere GraphQL security como parte do seu programa de segurança de software.

Precisa Avaliar a Segurança das suas APIs GraphQL?

Oferecemos pentest especializado em GraphQL, code review e implementação de controles de segurança.

Falar com Especialista
Inteligência Brasil

Inteligência Brasil

Consultoria especializada em Application Security e Segurança de APIs.