Introspección pública de GraphQL: por qué es un problema y cómo desactivarla
La introspección de GraphQL es la consulta integrada que devuelve el esquema completo de tu API: cada tipo, campo, argumento y mutación. Es esencial en desarrollo, pero no debería ser accesible en producción en APIs privadas. Si la dejas activada, es un mapa de toda la superficie de ataque de tu backend.
Qué es
Todo servidor GraphQL implementa un pequeño conjunto de metacampos, sobre todo __schema y __type. Un solo POST a /graphql con `query { __schema { types { name fields { name } } } }` devuelve la definición completa de tipos.
Herramientas como GraphiQL, Apollo Sandbox y la interfaz Playground dependen de la introspección para autocompletar consultas y mostrar el explorador del esquema. En desarrollo es justo lo que quieres; en producción, en una API privada, significa que cualquiera en el mundo puede descargar el mismo mapa.
Por qué importa
El esquema nombra tus modelos, tus relaciones y cada mutación que expones, incluidos campos de administración, internos y obsoletos que nunca debieron descubrirse desde fuera. Los atacantes lo usan para elaborar una lista dirigida de operaciones con las que buscar fallos de bypass de autenticación, IDOR e inyección.
Aunque todos los campos estén correctamente autorizados, mutaciones ocultas como refundOrder, impersonateUser o exportBackup no deberían anunciarse. La introspección convierte la fase de reconocimiento del atacante de horas de adivinanzas en una sola petición.
Cómo solucionarlo
Desactiva la introspección cuando NODE_ENV sea production. Mantenla activada en local para que tu equipo pueda seguir explorando el esquema en el Sandbox.
import { ApolloServer } from "@apollo/server";
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: process.env.NODE_ENV !== "production",
});Yoga tiene un plugin oficial; graphql-http expone una regla de validación de graphql-js. Ambos detienen las consultas de introspección antes de que se ejecuten.
// GraphQL Yoga
import { createYoga } from "graphql-yoga";
import { useDisableIntrospection } from "@graphql-yoga/plugin-disable-introspection";
export const yoga = createYoga({
schema,
plugins: process.env.NODE_ENV === "production" ? [useDisableIntrospection()] : [],
});
// graphql-http (or express-graphql)
import { NoSchemaIntrospectionCustomRule } from "graphql";
const validationRules = process.env.NODE_ENV === "production"
? [NoSchemaIntrospectionCustomRule]
: [];GraphiQL, Playground y Apollo Sandbox existen para ayudar a las personas a explorar el esquema; no tienen cabida en un endpoint público de producción. Protégelas con una comprobación de autenticación o no las montes en el build de producción.
Desactivar la introspección es un paso de hardening, no un control de acceso. Cada campo sigue necesitando una autorización adecuada a nivel de resolver; de lo contrario, cualquiera que adivine el nombre de un campo puede seguir llamándolo. Trata la introspección como una capa más, no como la única.
Preguntas frecuentes
¿Ocultar el esquema no es simplemente seguridad por oscuridad?
En parte, sí: un atacante decidido puede seguir adivinando nombres de campos por fuerza bruta. Pero vale la pena no ponerle el reconocimiento fácil y completo. Todas las guías comerciales de APIs GraphQL y la cheat sheet de GraphQL de OWASP recomiendan desactivar la introspección en producción.
¿Y si tengo una API pública y quiero que los desarrolladores exploren el esquema?
Publica el esquema de forma deliberada: comparte un archivo en Schema Definition Language, aloja un sitio de documentación o expón la introspección solo tras la autenticación. Eso es muy distinto de que un POST anónimo lo devuelva todo.
¿Cómo lo detecta AppSafe?
AppSafe envía por POST una pequeña consulta de introspección a /graphql y /api/graphql y busca una respuesta __schema con estado 200. Si la recibe, lo marca con severidad media en la categoría Seguridad de API.
¿Tu app está afectada?
AppSafe verifica este y docenas de problemas más en un solo escaneo gratis.
Escanear mi app gratisGuías relacionadas
CORS mal configurado: las trampas del comodín y del reflejo
Permite todos los orígenes y cualquier sitio podrá leer tu API.
Páginas de error detalladas y stack traces en producción
Un stack trace le dice al atacante exactamente dónde apuntar.
Métodos HTTP peligrosos: cómo se anuncian TRACE, PUT y DELETE
Una respuesta OPTIONS que lista TRACE o DELETE revela más de lo que debería.
API keys expuestas en el JavaScript del cliente
Todo lo que va en tu bundle es público. Trátalo como tal.