Intro to GraphQL – Attack Scenarios
GraphQL is one of the commonly used open-source manipulation and data query language for APIs, and runtime for implementing queries for preexisting data. It also serves as an efficient alternative to traditional REST API queries. This open-source language is not associated with a specific backend, which means that it interacts with existing code and data. The client interacts with the GraphQL service, which then interacts with the database via query resolvers during execution.
It enforces a strict typing system, and data is described in a well-defined GraphQL schema. It enables clients to craft a GraphQL query and get what they need. Their schemas can be massive, and from a hacker’s perspective, this presents new challenges. The foundational knowledge of the GraphQL schema and proper tools for automation is necessary to plan an attack.
- Query: A read-only operation to fetch data from a GraphQL service.
- Mutation: GraphQL data manipulation via mutation, in addition to its most common use case of fetching data.
- Field: The basic unit of data that can be fetched. It is all about the selection of fields on objects.
- Argument: Every field and nested object can have an argument, enabling the client to filter the results.
- Alias: Aliases are used for avoiding the naming conflicts in the results. For example, the client may start a query of the same object with different arguments and retrieve the results in different aliases.
- Fragment: Fragments are those sets of queries that can be reutilized across multiple queries.
- Variables: Variables can be used in queries or mutations to create objects with dynamic arguments.
The above image contains a query operation on the object ‘paste’. The object takes an argument ‘pId’, which is a string, and a variable ‘$pId’. It is also defined to make this argument dynamic.
Finding GraphQL endpoints
Some common examples for GraphQL endpoints are listed below.
Browse SecLists some popular graphql wordlist.
Check for parameters that resemble GraphQL query structure, then locate hidden endpoints by looking out for keywords in the HTML source of your web application or files such as, “query “, “mutation “, “graphql”.
However, the endpoints do not have to follow any specific naming convention. Applications in the wild are known to host their GraphQL service on a separate domain e.g.,graphql.example.com.
After identifying a GraphQL endpoint, the first step would be an introspection query. Most GraphQL instances have introspection enabled by default.
An introspection query is used to probe a GraphQL service for information about the types, queries, mutations & fragments of the available GraphQL schema. This feature allows anyone to see the layout of the entire schema. If the introspection is documented by the developers, then it can be accessed by the GraphQL endpoint via its interactive console (usually /graphiql).
A comprehensive request to perform GraphQL introspection(if enabled) is shown in the following image:
Visit Payloads All The Things to learn more information on the URL encoded & URL decoded variants of the GraphQL introspection query. Tools like GraphQL Raider and InQLare used to gather information about queries and mutations.
Common GraphQL Attack Scenarios
We will be looking at a couple of attacks that consist of scenarios specific to the GraphQL implementation like Batched Queries and DoS from Nested Queries. However, classic attacks like SQL injections, Rate Limiting, and Improper Authorization also affect GraphQL implementations.
Batched Queries Attack
GraphQL supports query batching. It enables the client to batch multiple queries or collect the request for multiple object instances through a single GraphQL API call.
This feature of grouping can be abused to create a form of brute force attack. As the client can query the same object multiple times with different arguments in a single API call, this attack is not as easily detectable as the usual brute force attack. This is because normally brute-force attacks utilize a massive number of requests. Here is an example of query batching:
In this example, the ‘systemDiagnostics’ operation (or object) is being queried multiple times with different values passed in the arguments for individual queries. This attack will likely bypass any existing rate limits in the application and will assist the attacker significantly in enumerating a large number of objects. To mitigate this type of attack, it is recommended to prevent batching for sensitive objects and implement object request rate-limiting in code.
Denial of Service
In GraphQL, query depth limitation is disabled by default, hence nested queries of massive depth can be executed to cause a denial-of-service attack on the GraphQL service. Because of the nature of the GraphQL query language, multiple queries can be nested one inside the other (refer to the image).
In GraphQL, when object types reference each other, it is often possible to build a circular query that grows exponentially to a point it could bring the server down due to resource exhaustion. In the example shown above, the application offers two object types, namely Owner and Paste, which reference each other (an owner has a paste, and a paste has an owner), permitting a recursive query to be carried out successfully.
Setting a max_depth for queries can help mitigate this type of attack. The max_depth functionality is the maximum level of depth allowed for a query, ensuring deeply constructed queries will not be accepted by GraphQL.
References and further reading
If you would like to delve deeper into this topic, here are some recommended resources:
- https://blog.yeswehack.com/yeswerhackers/how-exploit-graphql-endpoint-bug-bounty/ – A beginner-friendly blog with some interesting information about introspection and authorization issues in GraphQL.
- https://jondow.eu/practical-graphql-attack-vectors/– A brief write-up detailing info about various GraphQL attack vectors.
Attack & PenTest Team
Varutra Consulting Pvt. Ltd.