Protecting Your GraphQL API From Security Vulnerabilities

Tom Nagle
Tom Nagle
Dec 5, 2019 · 4 min read

GraphQL is quickly becoming the tool of choice for developers that need to build an API for their client application. But like all new technologies, GraphQL comes with its own threat landscape. Whether you’re building a side project or a large-scale enterprise application, you’ll need to make sure you’re protecting yourself against these GraphQL security vulnerabilities.

Image for post
Image for post

While the threats listed in this post are specific to GraphQL, your implementation will introduce a new set of threats that have to be addressed. It’s also important that you understand the threats that put every application exposed to the internet at risk.

Threat: Large, deeply nested queries that are expensive to compute

Solution: Depth limiting

The power that GraphQL provides comes with some new security threats. The most common is deeply nested queries that result in expensive computations and large JSON payloads that can disrupt your network quality, or take it down altogether.

The right way to protect your API from this kind of attack is to limit query depth so maliciously deep queries are blocked before the result is computed.

GraphQL Depth Limit provides an easy interface for limiting the depth of all queries.

Threat: Brute forcing vulnerable mutations

Solution: Rate limiting

Brute forcing login forms is the oldest trick in the hacking book. In the past decade, the internet has experienced so many large data breaches that a pack of 772,904,991 unique emails and 21,222,975 unique passwords was recently exposed and reported by Troy Hunt of Have I been Pwned.

Breaches like this put every website and application exposed to the internet at risk. Attackers can hit your login mutation with emails and passwords that appear in these lists until they get the response that they’re looking for.

Fortunately, there is an easy way for you to make this really difficult and slow for attackers, making you a less appealing target.

This GraphQL Rate Limit plugin allows you to specify limits on your queries and mutations in three different ways, custom directives graphql-shield or with the base rate limiter function.

The plugin allows you to set the time window and a limit. Setting a large time window on highly vulnerable mutations and queries, like login and shorter limits on less vulnerable queries will help you maintain a nice experience for legitimate users and a nightmare for attackers.

Create a rate limit directive:

This is a unique identifier for each request. You can use the user’s IP address or another identifier that is unique to that user and consistent for every request.

Add the directive to your schema:

Finally, add the directive to your vulnerable mutation:

Threat: Allowing user input where you should infer it

Solution: Infer input from the user’s session where you can

It’s easy to think that if you want to allow a user to update a resource then you should let them specify what resource they want to update. But what if they get the ID of a resource that they don’t have CRUD privileges on?

Let’s say that we have an UpdateUser mutation that allows a user to update their profile.

Without any server-side protection, an attacker with a list of IDs would be able to update the email address for potentially any user. The obvious solution here is to add a test to make sure the current user’s ID matches the ID in the input fields.

Don’t do:

The less obvious but correct way to fix this problem is to not allow ID as an input and use the user’s ID from the context object.

Do:

While this may be a trivial example, doing this for every asset that has a one to one relationship with your user object can protect yourself against a lot of risky mistakes.

Threat: Running multiple, expensive queries simultaneously

Solution: Query cost limitations

By assigning a cost to each query and specifying a maximum cost per query, we can protect ourselves against attackers executing multiple expensive queries simultaneously.

The GraphQL Cost Analysis plugin is an easy way to specify costs and cost limits.

Specify your maximum cost:

Specify a cost for each query:

Threat: Exposing GraphQL implementation details

Solution: Disable introspection in staging and production

The GraphQL playground is an extremely helpful tool for development. It’s so powerful that it will even document your schema, queries, and subscriptions for you. This information could be a gold mine for attackers looking to find exploits in your application.

The GraphQL Display Introspection plugin will prevent your schema from being leaked in publicly facing environments. Simply import the plugin and apply it to your validation rules.

The Startup

Medium's largest active publication, followed by +756K people. Follow to join our community.

Tom Nagle

Written by

Tom Nagle

I am a full stack JavaScript developer, living in Melbourne, Australia. My preferred stack is Mongoose, TypeScript, Node.js, React & GraphQL.

The Startup

Medium's largest active publication, followed by +756K people. Follow to join our community.

Tom Nagle

Written by

Tom Nagle

I am a full stack JavaScript developer, living in Melbourne, Australia. My preferred stack is Mongoose, TypeScript, Node.js, React & GraphQL.

The Startup

Medium's largest active publication, followed by +756K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store