GraphQL pentesting: vulnerabilidades comunes en APIs GraphQL
GraphQL resuelve problemas reales de las APIs REST —over-fetching, under-fetching, versionado— pero introduce una superficie de ataque distinta que los tests pensados para REST no cubren bien. Un único endpoint, un esquema fuertemente tipado y consultas anidadas definidas por el cliente cambian por completo qué hay que probar y cómo.
Por qué GraphQL tiene una superficie de ataque distinta a REST
En REST, cada endpoint expone una operación concreta y el control de acceso se aplica habitualmente por ruta. En GraphQL hay un único endpoint (normalmente `/graphql`) donde el cliente compone la consulta: decide qué campos, qué relaciones anidadas y qué profundidad quiere resolver. Eso traslada gran parte de la lógica de control de acceso y de límites de recursos a cada resolver individual, y es fácil que algún resolver quede sin las mismas comprobaciones que el resto — un problema de superficie mucho más difícil de mapear automáticamente que en REST.
Introspection sin restringir: el fallo más común
GraphQL incluye por diseño una funcionalidad de introspection que permite consultar el esquema completo de la API: todos los tipos, campos, mutaciones y sus relaciones. Es imprescindible en desarrollo, pero dejarla activa en producción equivale a publicar la documentación completa de tu API interna a cualquiera que la pida. Es, con diferencia, el hallazgo más repetido en pentesting de GraphQL: permite a un atacante mapear en segundos campos y mutaciones sensibles (`isAdmin`, `internalNotes`, `deleteUser`) que nunca se documentaron públicamente pero que existen en el esquema.
Batching attacks y agotamiento de recursos (DoS a nivel de query)
Como el cliente compone la consulta, puede construir queries anidadas de profundidad arbitraria (alias batching, consultas circulares entre tipos relacionados) que fuerzan al servidor a ejecutar miles de resoluciones internas con una sola petición HTTP — invisibles para un WAF que solo cuenta requests por segundo. Sin límites de profundidad (`depth limiting`), de complejidad de query (`cost analysis`) o de número de alias por petición, una única consulta bien construida puede tumbar el servicio o agotar la base de datos. Es un vector de denegación de servicio que no existe de la misma forma en REST.
BOLA/IDOR en resolvers GraphQL
El fallo de control de acceso a nivel de objeto (BOLA, #1 del OWASP API Security Top 10) es tan relevante en GraphQL como en REST, pero más fácil de pasar por alto: cada resolver que devuelve un objeto por ID debe comprobar de forma independiente que el usuario autenticado tiene permiso sobre ese objeto concreto. En APIs grandes con decenas de resolvers, es habitual que algunos hereden la comprobación de autenticación (¿estás logueado?) pero no la de autorización (¿puedes ver ESTE recurso?) — permitiendo acceder a datos de otros usuarios cambiando simplemente el ID en la consulta.
FAQ
¿Basta con desactivar introspection en producción para estar seguro?
No. Desactivar introspection reduce la superficie de reconocimiento fácil, pero no corrige los fallos de control de acceso ni los de agotamiento de recursos — un atacante con conocimiento parcial del esquema (por ejemplo, a través del código cliente) puede seguir explotando resolvers vulnerables sin necesidad de introspection.
¿Un escáner automático detecta estas vulnerabilidades en GraphQL?
Detecta parcialmente introspection expuesta y algunos patrones conocidos, pero BOLA en resolvers específicos y los límites de complejidad de query requieren entender la lógica de negocio de cada mutación y relación — es terreno de pentesting manual, no de escaneo automático.