Introduction to GraphQL

Representational state transfer (REST) APIs are the most popular type of API.  However, GraphQL is rapidly growing in popularity as a competitor to REST.

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.

These differences between traditional REST APIs and GraphQL ones can create challenges for security.  Legacy web application firewalls (WAFs), which rely upon features like data in the URL to identify potential threats, are unable to detect and block attacks against GraphQL APIs.

Challenges of GraphQL Security

GraphQL APIs have a number of differences from REST APIs.  Among these are the lack of data in the URL, automatically generated data schemas, subqueries in requests, and variable response formats.  Each of these unique features creates challenges for WAFs securing GraphQL APIs.

URL Filtering Doesn’t Work

URL blacklisting and filtering is a common feature in WAFs.  This enables WAFs to enforce access control by blocking attempted access to privileged sections of the application.

securing graphql api 1

With GraphQL, this approach to security is ineffective.  All API requests to GraphQL, regardless of their purpose and intended target, go to the same URLs (/graphql and /api/graphql) as shown in the image above.  As a result, it is necessary to perform any filtering, access control, etc. at the HTTP request level rather than inspecting URLs.  Since this data is all encoded in JSON, a WAF must be capable of parsing JSON data and making access decisions based upon the result.

Built-in Data Schema

With REST APIs, the application defines the schema used to structure the data and enforces its consistency. The same is not true of GraphQL.

GraphQL creates its own data schemas automatically and handles consistency enforcement.  This schema is accessible via an Introspection query and is usually publicly accessible.  Blocking this attack vector requires disabling Introspection queries.

Multiple Calls Per Request

With a REST API, functions and handlers are used granularly for each request.  This makes it possible to block any inappropriate requests without impacting the rest of the applications operations.

GraphQL, on the other hand, allows multiple API function calls within each request.  These multiple calls are defined as subqueries, and, in order to secure GraphQL, a WAF must be capable of parsing these subqueries and making the appropriate access decisions.

Variable Response Formats

With a REST API, the format of responses to a request are defined within an application’s code.  This makes it easy for a WAF protecting the application to parse a response and take action accordingly.

In contrast, GraphQL allows the user to define the structure of the desired response within their query.  While this is a useful feature for the user, it complicates security since variable response formats complicate parsing and may be used maliciously to hide data exfiltration or other attacks from a WAF.

The GraphQL Attack Surface

As an API, GraphQL presents an enticing target to cybercriminals.  Exploiting the API code can enable them to gain access to sensitive data or protected functionality within an application.  While GraphQL APIs share many of the same risks and attack vectors as REST APIs, they also have unique ones created by the differences between how the two types of APIs operate.

Injection Attacks

Injection attacks take advantage of poor input validation by an application.  Typically WAFs detect these attacks based upon signatures.  For example, a WAF may look for quotation marks and SQL comment characters when inspecting a request to an SQL database.

SQL injection in a GraphQL query

However, this approach to security only works if requests match a format for which the WAF has a signature.  GraphQL uses the JSON format to encode request data, and this new format can enable malicious requests to bypass a WAF’s protection.  The screenshot above includes an example of this, where a malicious input takes advantage of an injection vulnerability.

Authentication Bypass

To an attacker, API documentation is a hugely valuable asset.  With full documentation of an API’s functionality, an attacker can look for exploitable vulnerabilities within the code.  As a result, it is important to limit access to information about the existence of protected and sensitive member functions in the API and how they function.

With GraphQL, this is more challenging than it would appear.  By default, the GraphQL schema, which defines all of this sensitive information, is publicly available via an Introspection request.  Unless a developer has configured a framework to disable these queries, any unauthenticated user can collect valuable details about the functionality of a GraphQL API.

Insecure Data Mapping

GraphQL is designed to provide direct access to data via an API.  While this is a valuable feature for legitimate users, it is also useful for attackers.

This direct access to data could enable an attacker to perform large-scale data exfiltration from an unprotected application via a GraphQL API.  Because GraphQL allows the user to define the format of the response to their request, an attacker may be able to define requests in a way that a traditional WAF would not be capable of detecting the attack.

Automated Attacks

Automated attacks are a growing threat to web application security and usability.  In 2019, malicious bots accounted for 20% of all Internet traffic.

Bot-driven traffic can have a number of different impacts on an application’s GraphQL API.  However, one of the biggest threats is a Denial of Service (DoS) attack.  By exceeding the query depth level or maximum data size that an application can process, an attacker could cause the application to crash or render it incapable of receiving and processing legitimate requests.

Batching Attacks

Unlike REST, GraphQL allows a user to perform multiple queries in a single request.  This is a useful feature for legitimate users but can also be exploited by an attacker.

An example of batch processing requests:

[
  {
    query: < query 0 >,
    variables: < variables for query 0 >,
  },
  {
    query: < query 1 >,
    variables: < variables for query 1 >,
  },
  {
    query: < query n >
    variables: < variables for query n >,
  }
]

And here is an example query of a single batched GraphQL call requesting multiple different instances of the droid object:

query {
  droid(id: "2000") {
    name
  }
  second:droid(id: "2001") {
    name
  }
  third:droid(id: "2002") {
    name
  }
}

The screenshot above shows one example of a GraphQL batching attack.  This request is directed to a GraphQL API that has two-factor authentication enabled using one-time codes.

However, the batching option in GraphQL enables an attacker to try multiple versions of the one-time code within a single request.  The same technique can be used to enable brute-force password guessing attacks and similar authentication bypasses.

Securing GraphQL with Wallarm

The unique features of GraphQL can make it challenging for WAFs to secure.  However, Wallarm has a number of features uniquely suited to securing an application’s GraphQL APIs:

  1. HTTP Parsing: Wallarm inspects the data contained within an HTTP request rather than just its headers.  This is vital for GraphQL security since the same URLs are used for all requests.
  2. JSON Inspection: Wallarm supports the JSON encoding format, enabling it to parse and inspect the data contained within GraphQL requests and responses.
  3. Signature-Free Detection: Wallarm uses detection rules generated by machine learning rather than relying on signatures.  This allows it to adapt to and detect attempted injection attacks taking advantage of GraphQL’s new format.
  4. Passive Scanning: Wallarm verifies application responses to client requests.  This detects and blocks successful data exfiltration or injection attacks based upon their results.

While legacy WAFs may be capable of blocking a range of attacks against REST APIs, they lack the features required to secure GraphQL.  Wallarm’s unique combination of features enables it to protect GraphQL APIs and operate in full blocking mode with minimal false positives.

Watch the video:

You can schedule a demo below: