Come funziona questo controllo
Scanaris invia una richiesta POST con la query di introspezione più piccola possibile, {__schema{queryType{name}}}, a tre percorsi dove di solito vive un endpoint GraphQL: /graphql, /api/graphql e /v1/graphql. Se uno risponde 200 e il corpo contiene __schema o queryType, l'introspezione è abilitata e apre un rilievo di gravità media con il percorso. Se non c'è GraphQL nel tuo sito, nessun percorso risponde così e non c'è rilievo. La query è di sola lettura, non tocca dati, e passa per gli stessi limiti di tempo e dimensione del resto della scansione.
Perché è importante
L'introspezione è la funzione di GraphQL che permette di chiedere all'API il suo stesso schema: tutti i tipi, tutti i campi di ogni tipo, tutte le query e mutation disponibili, con i loro argomenti. In sviluppo è indispensabile: la usano il playground, l'autocompletamento dell'editor e i generatori di codice. In produzione, aperta a chiunque, è una mappa completa del tuo backend. Un attaccante vede che esiste una mutation deleteUser(id) o un campo internalNotes senza doverli indovinare, e va dritto a provare se l'autorizzazione di ciascuno è fatta bene. Per questo è gravità media: da sola non espone dati, ma rende banale trovare qualsiasi altra falla di permessi.
Come disattivarla in produzione
- Apollo Server:
introspection: "production" !== 'production'alla creazione del server. Da Apollo 4 è già disattivata quandoNODE_ENVèproduction; se la vedi attiva, controlla che quella variabile arrivi davvero al tuo deploy. Disattiva anche la landing page o il playground in produzione. - GraphQL Yoga ed Envelop: il plugin
useDisableIntrospection()di@envelop/disable-introspection, condizionato all'ambiente. - Hasura (il percorso /v1/graphql): nelle impostazioni di sicurezza del progetto c'è un controllo dell'introspezione per ruolo (Cloud ed Enterprise). Assicurati inoltre che il ruolo pubblico abbia permessi minimi e che il segreto di amministrazione non viaggi mai fino al browser.
- graphql-ruby:
disable_introspection_entry_pointsnella classe dello schema. - Python (Graphene, Strawberry, Ariadne): aggiungi la regola
NoSchemaIntrospectionCustomRuledigraphql-corealle regole di validazione in produzione. - .NET (Hot Chocolate):
.AllowIntrospection(false)o l'opzione per modulare l'introspezione per richiesta in base a un header o a un ruolo.
Disattivare l'introspezione non sostituisce l'autorizzazione: ogni query e mutation deve verificare chi chiede. Affiancale limiti di profondità e complessità delle query (evitano query annidate che mettono giù il server) e, se il tuo server lo permette, disattiva anche i suggerimenti sui campi ("Did you mean…"), che fanno trapelare nomi anche con l'introspezione chiusa.
Verifica che sia risolto
curl -s -X POST https://tuodominio.it/graphql -H "Content-Type: application/json" -d '{"query":"{__schema{queryType{name}}}"}'
Ripeti con /api/graphql e /v1/graphql. Atteso: un errore del tipo "introspection is not allowed", un 400 o 403, oppure un 404 se lì non c'è GraphQL. Se vedi "queryType":{"name":"Query"}, è ancora aperta.
Domande frequenti
La mia API è pubblica e documentata. Mi riguarda?
Se pubblichi lo schema apposta, l'introspezione aperta non rivela nulla di nuovo e puoi dare il rilievo per accettato. La maggior parte delle API applicative non è in quel caso: hanno mutation interne che nessuno dovrebbe conoscere.
Il mio endpoint è su un altro percorso. Non viene controllato?
Si provano solo i tre percorsi più comuni. Se il tuo vive altrove, fai il test qui sopra con il tuo percorso reale. Altri pannelli ed endpoint di sviluppo che non dovrebbero rispondere in produzione li cerca endpoint esposti.
E se l'endpoint richiede autenticazione?
Allora l'introspezione risponde 401 e non viene segnalata. È la situazione corretta: un attaccante senza sessione non ottiene lo schema. Controlla che l'header CORS dell'API non sia aperto a qualsiasi origine; lo guarda CORS permissivo.