GraphQL APIs are often a black box, but Burp Suite’s introspection capabilities can turn them into an open book.
Let’s see what this looks like in practice. Imagine you’re testing a GraphQL endpoint at http://localhost:4000/graphql.
First, you need to enable Burp’s GraphQL support. Go to your Burp Suite Proxy settings, then the "Intercept Client Requests" tab. Under "Websockets, GraphQL, etc.", ensure "Intercept GraphQL requests" is checked.
Now, send a GraphQL query through Burp. A common query to fetch data might look like this:
query {
users {
id
username
email
}
}
When this request hits Burp, you’ll see it in the Proxy History. The key is that Burp will now automatically attempt to parse and display the GraphQL schema if it’s available.
If Burp successfully retrieves the schema, you’ll see a new tab appear for the request: "GraphQL". This tab shows a structured view of your API’s schema. You can browse through types, fields, queries, and mutations.
This introspection is usually enabled by default on GraphQL servers. It’s a feature designed to help developers understand and interact with their API. For Burp, it means we can leverage that built-in documentation.
The "GraphQL" tab in Burp allows you to:
- View the Schema: See all available types, fields, and their relationships.
- Generate Queries: Build valid queries based on the schema, reducing guesswork.
- Explore Mutations: Understand how to modify data and what arguments are required.
- Identify Entry Points: Discover all possible queries and mutations.
To get a deeper dive, let’s look at the actual configuration and behavior. When Burp intercepts a request to a GraphQL endpoint, it looks for specific patterns. If the Content-Type is application/json and the POST body contains a JSON object with keys like query, variables, or operationName, Burp flags it as a potential GraphQL request.
The real magic happens when the server responds with its schema. This response is typically served via an endpoint like /graphql itself, often triggered by a specific introspection query like {"query": "{ __schema { types { name } } }"}. Burp’s GraphQL parser automatically detects this schema information and populates the "GraphQL" tab.
Here’s a simplified example of a schema response that Burp would parse:
{
"data": {
"__schema": {
"types": [
{
"name": "Query",
"fields": [
{
"name": "users",
"type": {
"kind": "LIST",
"ofType": {
"kind": "OBJECT",
"name": "User"
}
}
}
]
},
{
"name": "User",
"fields": [
{ "name": "id", "type": { "name": "ID", "kind": "SCALAR" } },
{ "name": "username", "type": { "name": "String", "kind": "SCALAR" } },
{ "name": "email", "type": { "name": "String", "kind": "SCALAR" } }
]
}
]
}
}
}
Once Burp has this schema, you can right-click on the request in the Proxy History, go to "Do active scan", and select "GraphQL schema discovery". This will perform automated checks against your schema.
Even without active scanning, the "GraphQL" tab itself is a powerful tool. You can use it to construct new requests. For instance, if you want to fetch a specific user, you can build a query like this directly in Burp:
query GetUserById($userId: ID!) {
user(id: $userId) {
id
username
email
}
}
And then provide the variables in the "Variables" field within the Burp GraphQL tab:
{
"userId": "123"
}
This interactivity allows you to dynamically explore the API’s capabilities without needing external tools or manually crafting every request. It’s like having a live, interactive API documentation that’s integrated with your security testing workflow.
The most surprising thing about GraphQL introspection is how easily it can be exploited if not properly secured. By default, many GraphQL servers expose their entire schema, revealing all available queries, mutations, and types. This can be a goldmine for attackers, as it provides a complete map of the API’s functionality, including potential weaknesses.
The "GraphQL" tab in Burp Suite is not just for viewing the schema; it’s an interactive playground. You can modify existing queries, change arguments, and immediately send them to the server to observe the responses. This rapid iteration is crucial for identifying vulnerabilities like excessive data exposure or insecure direct object references.
After you’ve successfully used introspection to map out your GraphQL API, the next logical step is to start fuzzing those discovered fields and arguments for common vulnerabilities.