GraphQL is quickly becoming the alternative to REST API, being able to request a specified set of data across multiple resources within a single request. But with great power come great security risks. A single point of failure could allow attackers to create complex queries and exhaust resources (DoS), or bypass authorization to retrieve unauthorized information.
In simple words, GraphQL is a query language for API endpoints. It interacts with API endpoints and fetches data from the backend. It’s an alternative for API standards like REST and SOAP. It can do most of the things that standard REST API endpoints can do and sometimes even more in an efficient and controlled manner.
In addition to this, it solves a lot of the problems that developers face when working with the REST API, like fetching more data than what’s needed or the need to have a new endpoint for every call.
GraphQL is a query language for your API, and a server-side runtime for executing queries using a type system you define for your data. GraphQL isn’t tied to any specific database or storage engine and is instead backed by your existing code and data.
There are 2 main request types in GraphQL — Query and Mutation.
Query: A Query is used to read data.
{
"data":{
"todos":[
{
"title": "Learn GraphQL"
},
{
"title": "Learn about queries"
}
]
}
}
The query and the response have a similar format, demonstrating that you’ll get what you ask for in GraphQL. For instance, in the screenshot above, we queried for the title. This means that we’ll get the title in the subsequent response.
Mutation: A Mutation is used to insert, update, or delete the data.
mutation{
insert_todos(objects:[{title:"Learn GraphQL"}]){
Returning{
Id
Created_at
}
}
}
For instance, the screenshot above depicts a mutation that adds a new Todo note. If successful it will return the id and the creation date of the newly inserted Todo note.
It’s difficult to list all endpoints in a GraphQL instance but many implementations use a framework like ‘Appollo’. The following section lists common endpoints used in GraphQL implementations:
A GraphQL schema is at the core of any GraphQL server implementation. It describes the functionality available to clients that connect to the GraphQL instance. It’s like a blueprint that clients can learn by querying for it.
To get the schema we can send an HTTP request to the GraphQL server endpoint asking for the GraphQL schema. This type of HTTP request is called a GraphQL introspection query.
Introspection is the main ability to query which resources are available in the schema. With introspection, we can see the queries, types, fields, and directives it supports. The introspection query is unfortunately turned on by default, so it is worth trying during a penetration test.
The introspection query gives us details about queries, types, fields, and directives that are supported by GraphQL and by default we can use the introspection query on every GraphQL instance. Let’s look at an introspection query in action.
Step 1: Intercept the HTTP request using Burp Suite:
Step 2: Send the HTTP request to Burp Repeater:
Step 3: Replace the POST body with a generic introspection query to fetch the entire backend schema. For this, we have used the ‘GraphQL Raider’ extension of Burp Suite.
Step 4: Capture the schema to gather sensitive API calls.
Sample Introspection Query:
{“query”:”\n query IntrospectionQuery {\r\n __schema {\r\n queryType { name }\r\n mutationType { name }\r\n subscriptionType { name }\r\n types {\r\n …FullType\r\n }\r\n directives {\r\n name\r\n description\r\n locations\r\n args {\r\n …InputValue\r\n }\r\n }\r\n }\r\n }\r\n\r\n fragment FullType on __Type {\r\n kind\r\n name\r\n description\r\n fields(includeDeprecated: true) {\r\n name\r\n description\r\n args {\r\n …InputValue\r\n }\r\n type {\r\n …TypeRef\r\n }\r\n isDeprecated\r\n deprecationReason\r\n }\r\n inputFields {\r\n …InputValue\r\n }\r\n interfaces {\r\n …TypeRef\r\n }\r\n enumValues(includeDeprecated: true) {\r\n name\r\n description\r\n isDeprecated\r\n deprecationReason\r\n }\r\n possibleTypes {\r\n …TypeRef\r\n }\r\n }\r\n\r\n fragment InputValue on __InputValue {\r\n name\r\n description\r\n type { …TypeRef }\r\n defaultValue\r\n }\r\n\r\n fragment TypeRef on __Type {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n ofType {\r\n kind\r\n name\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n }\r\n “,”variables”:null}
The response may be quite big and hard to understand. The best way to understand the response is to visualize it. This can be done by using the ‘Voyager’ tool.
To get the same result as above, perform an introspection query on the target and paste the response in the ‘Voyager’ tool. Using this method, attackers can easily identify sensitive API calls and exploit them.
We will be exploring more attack vectors in Part 2 of the Hacking GraphQL series.
Stay safe, stay healthy and hack responsibly.
By partnering with Redfox Security, you’ll get the best security and technical skills required to execute an effective and thorough penetration test. Our offensive security experts have years of experience assisting organizations in protecting their digital assets through penetration testing services. To schedule a call with one of our technical specialists, call 1-800-917-0850 now.
Redfox Security is a diverse network of expert security consultants with a global mindset and a collaborative culture. If you are looking to improve your organization’s security posture, contact us today to discuss your security testing needs. Our team of security professionals can help you identify vulnerabilities and weaknesses in your systems and provide recommendations to remediate them.
“Join us on our journey of growth and development by signing up for our comprehensive courses.“
Redfox Cyber Security Inc.
8 The Green, Ste. A, Dover,
Delaware 19901,
United States.
info@redfoxsec.com
©️2024 Redfox Cyber Security Inc. All rights reserved.