Denial of Service (DoS) attacks in GraphQL APIs are nothing new. It turns out that when you let clients control what data they want to receive from the server, malicious users try to abuse this flexibility to exhaust resources. Who could have guessed it?
But when we talk about preventing DoS in GraphQL, we’re usually discussing how to handle complex queries with deeply nested or circular relationships or even about preventing batching attacks, but it’s not often that alias and directives are mentioned as potential vectors.
GraphQL’s alias feature allows a client to perform the same operation multiple times in the same HTTP request, which is typically not possible, by attributing a name (or alias) to each “result”.
From the docs:
Directives, on the other hand, are a way to conditionally include or exclude fields, fragments, or even top-level operations.
Again, from the docs:
So, a GraphQL server will let you perform the same query multiple times in a single request if you assign a different name to each of them, and it might also allow you to use the same directive multiple times in a single query, multiplying the results.
You can see how these features may be useful to an attacker when looking for ways to perform a DoS attack.
Tools like graphQL-cop make testing these scenarios much easier:
Note that the --proxy option sends the requests through 127.0.0.1:8080 which lets us further inspect them.
As you can see below, in the highlighted query, the tool tries to request the same field (__typename) with 100 different aliases:
Although the tool marked this API as vulnerable to “Alias Overloading” since the request is successful, note that there may be optimizations in place that actually resolve all of these separate queries as a single one - a slow successful response should be a better indicator that DoS may be possible.
In this particular API, we can see that there’s a difference of only 2 milliseconds between using 10 aliases or 100 aliases, which means that the server is probably not performing separate operations for each alias when fetching this specific field:
The tool also tests “Directive Overloading” by attempting to send the same directive multiple times in the same query which, in the example shown below, produces an error:
If the results are multiplied, then it may indicate that the server is vulnerable. However, a slow response with multiplied results is a more accurate indicator.
If you’re worried about protecting your GraphQL API, you should understand how your particular GraphQL server handles these features. The good news is that if you already have measures in place to protect against other vectors of DoS, they will probably be effective against this type of attack as well.
Well-known techniques, such as query complexity analysis, complexity-based rate limiting, or implementing timeouts to “kill” queries that take too long to resolve can be highly effective. Moreover, you can maintain a list of pre-approved operations that the server can execute, which prevents malicious users from building “custom” vulnerable queries.