GraphQL is an alternative to the REST concept that allows working with the data in a more structured and object-oriented way. This technology is very famous and used by many enterprise companies such as Facebook, Walmart, Intuit among other. Whether you know it or not, GraphQL has a significant impact on your business. Many products you rely on, such as GitLab, New Relic, and WordPress use GraphQL under the covers. In this series of articles, we will explore GraphQL from the security angle, explain common attacks and vulnerabilities found so far, and give advice on how to protect GraphQL APIs.
Unlike REST, where you need to define your schema externally, for example, using Swagger, GraphQL will guarantee consistency of your schema and API itself. They describe themselves as:
GraphQL is a query language for your API, and a server-side runtime for executing queries by using a type system you define for your data. GraphQL isn’t tied to any specific database or storage engine and is instead backed by your existing code and data.
Our own definition of GraphQL is a meta-layer with built-in query language to access object-oriented data. It’s based on JSON-encoded HTTP requests with custom queries inside. Unlike REST, there is no data inside the URL.
What types of attacks can compromise GraphQL?
First of all, the GraphQL security testing guides start from Introspection queries (https://graphql.org/learn/introspection/), which allows attackers to obtain data schema and then build all the available queries and apply payloads there. So, the first advice is to disable the introspection option. Usually, GraphQL drivers for applications provide this configuration option, like this: https://webonyx.github.io/graphql-php/security/#disabling-introspection. Unfortunately, it’s not the case for many drivers and products used GraphQL and you have to use an external application security solution to disable that.
Secondly, since GraphQL is a middleware API layer, almost all the attacks there are related to the security of your application under the hood.
We can classify all the typical issues related to GraphQL implementations into the following types:
- Input validation/injections
- Authentication/data access limitations bypass
- Insecure data mapping/sensitive information disclosure
- Function abuse/brute-force/automation
In the subsequent articles from this series, we will explain and discuss every single type described above in detail.
Is the risk real?
It is. Wallarm’s partner, Vulners, shows at least 61 records related to GraphQL vulnerabilities in the Vulners aggregated threat intelligence feed: https://vulners.com/search?query=graphql
Most of the issues are current as of this year. Here are some examples of the more interesting issues.
- WordPress was hacked by GraphQL plugin which allows to create admin users and upload shells because of that among other issues (https://www.pentestpartners.com/security-blog/pwning-wordpress-graphql/)
- Facebook Marketplace was affected (https://vulners.com/myhack58/MYHACK58:62201994269)
- Shopify got at least 12 GraphQL-related bugs with different level of risk from high to medium last year at HackerOne (read this https://hackerone.com/reports/419883 among others)
- HackerOne itself was vulnerable multiple times because of GraphQL (including SQL-injection https://vulners.com/hackerone/H1:435066)
- NewRelic got hacked through an authentication GraphQL issue (https://www.jonbottarini.com/2018/01/02/abusing-internal-api-to-achieve-idor-in-new-relic/)
- GitLab fixed at multiple GraphQL-related issues recently (https://about.gitlab.com/blog/2019/07/03/security-release-gitlab-12-dot-0-dot-3-released/#authorization-issues-in-graphql)
What can be done to protect my GraphQL API?
As always, the best way to protect anything is to apply secure coding practices, test for security issues before the application is released and limit the number of security issues in your code. At the same time, many parts of the application, like 3rd party libraries, web server, application server, database, and so on, are not actually developed by your team and often are not under their control. To mitigate, you typically need an additional layer of application protection, that can work with GraphQL APIs, such as Wallarm Advanced Cloud-Native WAF.Â
Unfortunately, you can’t use legacy WAFs, IDS/IPS, NGFW and other commodity tools because of the sophisticated data format it uses under the hood of HTTP. GraphQL request usually consists of three parts of data inside the JSON body: operationName
, query
and variables
.
It looks like this:
POST /graphql/ HTTP/1.1 HOST: myapp.local Content-type: application/json ... { "operationName":"inviteUser", "variables": { "input": { "email":"jack@wallarm.com", "firstName":"Jack", "lastName":"Daniels", "role":"REGULAR" } }, "query": "mutation inviteUser($input: InviteUserInput!) { inviteUser(input: $input) { user { firstName lastName email } __typename } }" }
As you can see, it’s a JSON data with a custom GraphQL query format in a “query parameter”. Because of the code-style format of such requests, it will cause signature triggers in WAFs/IPS all the time and the security team will simply disable it there. For example, mod_security CRS caused it as describe here: https://github.com/SpiderLabs/owasp-modsecurity-crs/issues/1006
A lot of other WAFs will easily pass all the JSON API requests without any filtration because they are not able to detect attacks within encoded GraphQL/JSON messages. Others will stop too many requests, cause a windfall of false positives and get turned off altogether.
Wallarm engineering team did a good job this year working around these issues to create a system that avoids false positives and bypasses for GraphQL attacks.
Wallarm implemented native JSON parser and specific rules to block GraphQL attacks. As a result, it’s possible now to block introspection queries and all the OWASP Top-10 attacks in the “variables” GraphQL parameters encoded as JSON.
As a result, when the next GitLab, WordPress, or other GraphQL-encoded vulnerability will be discovered, all the Wallarm customers will be protected automatically.