GraphQL vs REST API model, common security test cases for GraphQL endpoints .

just_a_noob
Dec 7, 2019 · 6 min read

The traditional REST model is similar to doing following tasks like getting your shipments delivered to you, ordering food online i.e, two different activities hence two different calls. However, GraphQL is like having personal assistant that does tasks for you once you give the required details such as address and your interests where you can simply ask what you want and wait for them to get to you.In other words, GraphQL is a standard language that the assistant in the example uses to serve you your interests all at once. Every graphQL endpoints are handled by a GraphQL server such as Apollo server or the heroku based graph engine.

A little more technical now, REST API has few calls namely POST , GET, DELETE , PUT etc as their method of actions to perform multiple API operations. While typically REST APIs require loading from multiple endpoints, GraphQL APIs get all the data your app needs in a single request.This is done by making one endpoint as the graph endpoint that deals with multiple requests/queries at once.So all relevant data is retrieved from this endpoint. Normally this endpoint ends with following names : /graphql, /graph , /graphql.php. A simple difference in the way queries are carried in both REST and GRAPHQL APIs are as shown in the image below:

Sample REST API method calls.
Sample GraphQL API query calls.

Key terms in GraphQL:

In graphQL, the query is the request that you send for a response you ask for. You can fetch data and modify it if you are permissioned to in the form of a mutation(more like a function in programming terms).

A resolver tells GraphQL how and where to fetch the data corresponding to a given field.You can create your own resolver, these resolvers help in structuring the API schema. For example, you want to retrieve a name of an author and its book from a e-library website.You could define a resolver such as :

const resolvers = {
Query: {
author(parent, args, context, info) {
return find(authors, { id: args.id });
},
},
Author: {
books(author) {
return filter(books, { author: author.name });
},
},
};

The query, { author { books } }, will call the Query.author resolver first and pass its result to Author.books. The query result will contain the return value of Author.books nested under data.author.books.

So, that’s with the fundamentals . Let’s get to the common security test cases:

Disclaimer: Before getting into it , you may require an extension called GraphQL Raider and a grapql visualizer such as this one here:https://apis.guru/graphql-voyager/. ->with graphql-voyager you can visually explore your GraphQL API as an interactive graph diagram.You may also require GraphiQL GUI interace that can be downloaded online from the official website to help interact with the GrapQL Queries such as: https://electronjs.org/apps/graphiql .

Test case 1:

Identify the grapQL endpoint in the request as mentioned above it normally has /graph, /graphql in the request. Now, try running an introspection query into the query parameter.The introspection query is by default one that defined and is used to know about the schema defined by the graphQL server in place.You can get an introspection query from here: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/GraphQL%20Injection.

Copy the introspection query and paste it in the query parameter of the graphQL request and send it. If the introspection is enabled then it should give you a response with the schema used and sometimes gives out the mutation used as well in detail.

A sample response in JSON should look like the following:

In some cases, running the introspection query gives out sensitive details. You can look up the schema to check on retrieving sensitive information by using schema to write queries.

Test case 2:

If you see a schema response try visualising it using GraphQL-voyager tool sometimes it throws out few interesting things. You can see the diagramatic representation of all the endpoints and API calls relevant to graphQL . Thereby, you could check for authentication issues at each endpoint.

For example:

The above image describes GrapQL API endpoints and their required attributes to make a query and what they lead to.

Test case 3:

Download and Use the official GraphiQL GUI interface to check for available mutations. Sometimes a visualiser may not list out all the mutations available in rare cases the interface shall provide all the mutations available to query with.

In the above pic we used mutation available from MyMutations in the schema docs and written a query that follows the syntax of the defined mutation(in our example, modifyBug). Remember to follow the syntax and understand what arguments are to be given to the mutation (it is similar to writing a pre-defined function and passing it for invoking an action in programming terms).

For ex: modify Bug mutation takes text , id , private values as input. Pass these in the Query Variables input column.

A sample mutation with passing input to Query variables is shown below:

Disclaimer:if you come across an input parameter in a mutation that ends with “!” then assume that parameter as a mandatory parameter that needs to be passed.In our example there is none as such.

Before modifying we had the following:

before writing the mutation
after modifying using the mutation

hence we can check for access control checks on the GrapQL mutations from the GraphiQL interface.

Disclaimer:If we are unable to make any mutation calls we may get a row level security error which justifies that there are access-permissions in store and the graphQL server is properly configured.

In summation, test all the mutations and queries by rewriting them and look if there is any misconfiguration that could lead to sensitive information disclosure or privilege escalations.

Test case 4:

Fuzz for SQL errors in the input of Query variables column. At the end a graphQL server will interact with a database and fetch information from there so there persists a SQLi injection possibility although uncommon.

A sample of how an error may encounter :

There have been cases in GraphQL where SQL queries are handled without parsing thus leading to SQL query execution on the database and giving out information. A sample of such incident is shown below:

In conclusion, the security test cases are not just limited to these but are intersection of the above test cases and many more. Learning never ends and as the saying goes there maybe patches to software but not to human errors, practices so until then vulnerabilities shall always persist.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade