Avoid GraphQL Denial of Service attacks through batching and aliasing

Some of your users start complaining that your web application is not secure and that someone managed to log into their accounts… You look at the user history and network activity, but nothing looks wrong. However, you notice that your server is slower than usual.

Two days later, your application is down due to a DoS attack, i.e. too many requests crashed your service, and it is not available anymore. But your network activity seems pretty quiet, and you have a firewall that should have prevented the DoS. That’s weird, isn’t it?

From GraphQL Aliases to Batch Attacks

It comes from a super useful feature of GraphQL: aliases.

What are GraphQL aliases?

When making a query using GraphQL, the response has the same format as the query. But what about querying the same field with different attributes? Without aliases, this isn’t possible as JSON field names must be unique. Here is the example from the GraphQL documentation:

In the above example, the two hero fields would have conflicted, but since we can alias them to different names, we can get both results in one request.

This feature allows multiple queries to be sent with a single GraphQL request. This technique is called batching. Only one batch will transit on the network and then all queries will be executed sequentially.

Batch attacks with aliases

It is an easy way to bypass attempt and rate limits. Indeed, limits are usually set up on the number of API calls, but what if a single API call can create 10,000 database requests?

Tools responsible for securing web applications like firewalls and rate limiters cannot detect abnormal activities: they only monitor API calls…

Therefore, all your common protection mechanisms will fail to detect and deny a brute-force attack. So, an attacker can simply make one API call with hundreds of attempts to find user credentials (email, passwords). They can also bypass two-factor authentication (2FA) by sending all the token variants of the one-time password (OTP).

An attacker could use a simple example to try different credentials.

mutation {
	login(username: "Tom", password: "password")
    second: login(username: "Tom", password: "password123")
    third: login(username: "Tom", password: "TomTheBest")
}

And this is the server response.

{
	"login": null,
    "second": null,
    "third": "U12hshjy7187GFST67sljsqfyzj19snSHDghjQSzFsj"
}

In this case, the third password was correct, and the attacker could now log in as a legitimate user with the authentication token.

Another consequence of this attack is Denial of Service (DoS). Indeed, if the attacker uses a huge number of aliases, your server will have a lot of work to do and may be unable to handle it. This causes a slowdown or even a complete shutdown, i.e. your server becomes unresponsive (DoS). And again, your firewall can’t prevent this.

Is my application vulnerable to Denial of Service?

This is a question you should ask yourself… but figuring out the answer remains challenging! Indeed, GraphQL is new and lacks just lacked the proper tooling, many development teams are just skipping security...

That’s why at Escape, we created a scanner that specializes in GraphQL APIs. It can streamline this process by quickly identifying issues across your API endpoints and providing remediation snippets—all in as little as 15 minutes, without complex integrations or traffic monitoring.

Escape

Protecting your GraphQL API against Batch Attacks

The alias functionality cannot be directly disabled (at least not in the current implementation), and as it is a useful feature, it will not be the best option.

Instead, you must implement a validation process to ensure the query doesn’t contain more aliases than the chosen maximum. A good security practice is to deny by default. Here, it means denying aliases except when they are really useful. Therefore, in the configuration options, set the default value for query and mutation to 1 (i.e. '*': 1) and add custom values for specific fields if necessary.

At Escape, we also created GraphQL Armor, an open-source plugin for JavaScript GraphQL implementations, which brings security best practices by default to your API.

Want to learn more? Check out the following articles: