Security considerations with GraphQL
In this lesson, you learn about some of GraphQL's pitfalls and how to avoid them. We cover rate-limiting, abusive queries, authentication, and more.
We'll cover the following
GraphQL security
Introduction
When people first hear about GraphQL, it is often from an enthusiastic front-end developer who is talking about getting all the data you need in a single query.
This is convenient, but for a lot of people, they start to wonder if that is such a good idea. What if somebody asked for sensitive data? You can just get whatever you want from the server, right?
As you have seen in previous lessons, that is not the case. Just as with a REST API, you only expose data intentionally. So, you may have a supersecretdata
type, but it is up to you whether you allow that to be publicly accessible or not.
With that said, there are things you should be aware of with GraphQL, and we will do a quick tour of them here.
Rate limiting
In a typical REST scenario, you might want to restrict the number of times that a user can ‘hit’ or access your resources before you exponentially reduce the number of times you respond to that request. This is known as a “back off” algorithm.
In GraphQL, one of the advantages is that you can request a lot of data in a single query. However, this is also a major disadvantage.
It is one thing to request a small piece of data such as your username, but what if you were to request hundreds of thousands of records all at once? Traditional rate limiting does not work here, since you cannot restrict the number of queries. Instead, you need to think about the problem differently.
The issue here is one of query complexity. What does it cost for your server to respond with the requested data?
In production, it is typical to use a pre-made query complexity analyzer to estimate a cost for each query, and use that to determine whether the query should be permitted or not. As an example of such a tool, you can look at graphql-cost-analysis.
Before rushing to implement this, stop and consider if your API needs this kind of measure. Have a play around with some “nasty” queries and see how they affect your server. You may find that the scale you are working on does not merit the time invested in implementing cost analysis.
There are lesser measures as well, such as restricting the number of items returned by any query via a
max
value in pagination, or by restricting the depth of a query, such as its nested values.
Authentication
If you build an application of any meaningful complexity, then chances are that you will need to handle authentication at some point.
Before getting into this, you should know that it is not considered good practice to handle your authentication with GraphQL and offer a login
and logout
mutation.
Instead, it is simpler to handle authentication as a separate middleware in Express (or whatever framework you use), and allow your GraphQL server not to worry about the contents of tokens and other things. Instead, the GraphQL portion of your application should be stateless.
Adding authentication to GraphQL makes it stateful and vastly increases the security headaches in your schema. You will need to think about exactly which fields do and do not require an authorization token. This can lead to mistakes and vulnerabilities that can be avoided if the schema simply assumes it will always deal with an authentication user.
Authorization
Whereas authentication refers to the process of verifying a user’s identity, authorization is the process of checking whether a user has permission to do something.
To emphasize, authorization is best handled outside of GraphQL, as it is business logic and should not live within your data layer. If you define these rules in the GraphQL schema, then you will inevitably end up replicating them somewhere else, which leads to inconsistency and vulnerability.
With that said, it is possible to add scopes to your API to allow or deny a user the ability to complete an action. For example, you can prevent a regular user from editing someone else’s article.
If you decide to add authorization to your GraphQL Schema, a better approach is to use a library to manage this and to keep it simple to prevent it becoming overly difficult to reason with. A good library is GraphQL Shield ().
GraphQL Shield
Conclusion
Security should be at the top of your mind, no matter which application you write. Try to code defensively and assume that there will be people attempting to make your code do things that it should not.
GraphQL offers a lot of flexibility to developers, but that comes with some extra considerations, which can be confusing. As a rule of thumb, limit the types of queries a user can make, and default to a stateless GraphQL API where authentication and authorization are handled in the business layer.
Get hands-on with 1200+ tech skills courses.