While REST APIs are unlikely to become extinct very soon, GraphQL is rapidly gaining popularity among developers. GraphQL, which was launched by Facebook in 2015, has provided a unique and promising alternative to the traditional REST API. Many organizations, like Facebook, and Shopify, have since implemented GraphQL into their infrastructures.
As the title indicates, GraphQL, also known as "Graph Query Language," is a query language for APIs.
While SQL(Structured Query Language) is a query language for relational databases, GraphQL is a query language that enables the client to request data. GraphQL can be directly used as a backend server or connected with existing backend infrastructure to query data.
GraphQL aims to create client apps based on flexible formats for displaying their data requirements and interactions. One of the best features is that it is not database dependent and can be used with your existing database and infrastructure.
There are various reasons why GraphQL is a buzz in the industry. Let’s take a look at some of the advantages of GraphQL :
- In a GraphQL application, a GraphQL schema establishes a single source. It provides the organization with a method to integrate all of its APIs.
- It takes a single round trip to process calls to GraphQL. As a result, client requests are fulfilled without over-fetching, reducing the overall network calls.
- GraphQL is introspective. A client can request an available data types list based on the requirements. Also, this is perfect for creating documentation automatically, unlike REST where developers have to write & maintain documentation.
- Numerous open-source GraphQL extensions like Apollo GraphQL are available to provide functionalities that are not available with REST APIs.
- Clearly defined data types decrease confusion between the client and the server.
Users can use a standardized version of the HTTP protocol to submit their queries and receive their results in a scalable manner. In addition, GraphQL allows for server-side execution of API queries, which are created by the user and bound with the existing codebase and data.
Using GraphQL as a query language makes sense; after all, "QL" looked significant enough to be in the name. But what exactly are we asking? Let’s examine a sample query request, and the related response may be helpful –
In the above code snippet, we are trying to fetch a list of employees with the following fields: object's id, name, email, and age. A typical response we might receive is something like this:
Now things will start to get exciting as we can make requests like the following to fetch employees with a specific id (id 54 in this case):
The above code snippet may provide the JSON response as mentioned below:
One of the main advantages of GraphQL as a query language is that a client application can only ask for the data it requires and count on it being delivered consistently hence reducing network calls
Regarding GraphQL operations, queries and mutations are perhaps the most frequently performed from the client's perspective. A query is equivalent to read, and Mutations manage all the others (create, update, and remove). We will talk about the mutations in the GraphQL Attacks part.
GraphQL Attacks –
New vulnerabilities come with new technologies. For example, GraphQL does not provide authentication or input validation by default; it is the job of the developer to do so. As a result, GraphQL allows anyone to make malicious queries and fetch sensitive information without any authentication.
While it would be hard to define every possible endpoint for finding a GraphQL instance, many of them share the following common endpoints:
/graphql
/graphql.php
/graphiql
/graphql/console
/graphiql.php
Note: You can use FFUF and GraphQL endpoint wordlist to identify the endpoints.
Introspection Attack
We found a GraphQL endpoint and can now interact with it. The introspection attack is the first thing we may do and see whether it allows. it is frequently helpful to inquire about the kind of queries a GraphQL schema allows. GraphQL’s Introspection system allows us to obtain this.
If the target application is vulnerable to an introspection attack, you can see all relevant data to inspect and examine further. Remember that a successful introspection attack will help us exploit high-severity vulnerabilities.
GraphQL Introspection is a unique query that examines GraphQL for its schema using the __schema field.
If introspection is enabled on the target application, we can perform the request using the following Query to get complete schema such as mutation, Query, objects, etc.
Here’s a link to GraphQL introspection query you can use. Let’s use the query to see how it works.
Now that we have received the proper let’s use a GraphQL visualizer to get a better picture of the schema.
Now we can see a clear picture of GraphQL structure.
Introspection is not a weakness but a GraphQL functionality. However, if it is publicly available, attackers can send malicious to understand how things work and can misuse such sensitive information.
According to Apollo GraphQL, Introspection should only be enabled in the development phase and be set to false in the production environment.
Denial of Service (DOS) Attack
GraphQL is also concerned about outages, affecting the application server's accessibility and functionality. For example, when calling objects, it is necessary to call them in depth; otherwise, it may cause a Denial of Service (DOS) Attack.
You can run multiple queries in GraphQL without having to batch them together.
If batching is disabled, you may create a query made of several aliases executing the same Query or mutation; if the server does not examine the value of the Query, an attacker can overload the server's capacity by utilizing large queries via aliases hence resulting in excessive resource consumption.
In the Introspection visualizer, we see a query called "systemUpdate." The systemUpdate query checks if there is anything to update or not.
Imagine a scenario where we send a query to check systemUpdate repeatedly to the server. Hence it will result in the DOS Attack. Let’s understand this with an example:
Payload –
query {
q1: systemUpdate
q2: systemUpdate
q3: systemUpdate
}
In the above code snippet, q1, q2, and q3 represent the aliases.
Request –
Response –
As you can see, there is a delay in the response time which shows that our payload worked successfully.
Information Disclosure due to GraphQL Error
GraphQL provides an excellent developer experience, including capabilities that support building APIs like readable errors and recommendations.
Not all concepts are intended to be carried forward from the planning and development stage into production. For a public-facing application, if the GraphQL fields are not set to false, these can help attackers to fetch sensitive details about your model, schema, etc.
Inappropriate fields will cause GraphQL to expose fields with similar names –
query {
system
}
Field recommendations are not a vulnerability in and of itself, but the functionality you can exploit to gain more information into GraphQL's schema, particularly when Introspection is not authorized.
SQL Injection in GraphQL –
GraphQL provides functionality that allows users to supply inputs, and you can use input fields to retrieve or store data. GraphQL interacts with arbitrary code written by the users/attackers. GraphQL does not prevent all types of attacks; if it fails to validate and sanitize user inputs, the application may be vulnerable to SQL Injection (SQLi)) attacks. If the application doesn't appropriately sanitize user input, malicious payloads can be used to retrieve confidential and sensitive data from the SQL database.
The pastes operation's filter option enables escaping the SQL query and injecting a SQL payload. Here’s what the payload looks like:
Stored Cross Site Scripting Attack using Mutations –
New pastes can be created and imported using the GraphQL mutations createPaste and importPaste. You may use any character in the pastes without any limitations, which can result in a Cross Site Scripting (XSS) vulnerability because the pastes would render in the Public and Private pasting pages.
Payload –
Insert the mutation payload query in the POST request.
HTML Injection Attack using Mutations –
A paste can also contain HTML tags that would render in the application, leading to an HTML Injection, similar to the Cross-Site Scripting (XSS) vulnerability.
Insert the mutation payload query in the POST request.
GraphQL Mutation Attack –
Mutation queries the data storage for modified data and returns a value. Mutations are utilized when a web application performs data modification operations. It's capable of inserting, updating, and deleting data.
Consider you have the mutation "createStudent" that the GraphQL application uses to create student accounts. Name, Roll Number, and password are included in this mutation.
Sample query –
Now, an attacker can convert the above query into a malicious Query (adding a new field named role in this case).
For developers, the most challenging aspect of GraphQL is having specific access control for each request and developing a resolver that will interact with the necessary access controls.
Due to this issue, student account John can view and edit sensitive information like Question papers, Attendance, etc., that are only allowed for "role: teacher."
GraphQL Testing Automation using InQL Scanner
InQL Scanner
InQL can examine the outcomes of introspection queries and produce clear documentation in forms like HTML and JSON schema. InQL may create templates (with optional placeholders) for all recognized basic data types.
InQL Burp Suite Extension
In this mode, the tool will retain all its stand-alone script features while providing a convenient user interface for query manipulation.
https://github.com/doyensec/inql
5 Mitigations for GraphQL Vulnerabilities
- DOS attacks are technically possible, as seen in the GraphQL attack examples. Still, they can be mitigated by adding limits to incoming requests, checking that not a large volume of data is loaded in a single answer, and timeouts for each execution and response.
- Every bit of incoming data must undergo validation, which is an essential and trustworthy best practice.
- Always use parameterized queries in the backend application to perform operations based on user input.
- To ensure that only one request is handled at a time, developers must add prevention measures to the code. For example, the number of objects a user can request or the number of allowed queries can all be limited.
- To prevent data leaks, it is advised to disable Introspection in production.
GraphQL gives many services to developers, but attackers can use these to exploit organizations to obtain sensitive data from them. In conclusion, consistently implement GraphQL in compliance with security standards and best practices.
Explore more with a deep dive into GraphQL part 2.
References & Further Readings
Escape Tech: GraphQL Verbose Error Suggestion
Understanding and Exploiting Graph QL by Gupta Bless
Tutorial Point: GraphQL Mutation
Discovering GraphQL endpoints and SQLi vulnerabilities by Matías Choren