Technical

Configuring Safelisting in GraphQL for Gloo Gateway

In one of our previous blogs on GraphQL for Gloo Gateway, we introduced you to Automatic Persisted Queries, or APQs. Persisted queries allow you to cache queries on the GraphQL server side so that you can simply execute these queries with their hash value rather than sending the entire query over the wire on every request. This approach can improve the latency, throughput, and performance of your GraphQL environment.

In this blog we will look at another feature that utilizes the hash value of GraphQL queries: safelisting. Safelisting enables the GraphQL API provider to predefine a specific set of allowed queries to prevent your GraphQL servers from resolving potential malicious requests that can impact the security and performance of your environment.

Configuring Safelisting

To configure a GraphQL safelist, we use the GraphQLAllowedQueryPolicy Gloo Custom Resource (CR) in Kubernetes. Like the GraphQLPersistedQueryPolicy we discussed in our previous blog, this policy can be applied to routes based on Kubernetes labels. In the following example YAML file, the policy is applied to all routes with the label “route: bookinfo-graphql”:

apiVersion: security.policy.gloo.solo.io/v2
kind: GraphQLAllowedQueryPolicy
metadata:
  name: bookinfo-allowed-queries
  namespace: bookinfo
spec:
  applyToRoutes:
  - route:
      labels:
        route: bookinfo-graphql
  config
    allowedQueryHashes: 
      -<query_hash>

With the GraphQLAllowedQueryPolicy CR, you define the hash values (SHA-256) of the queries that are allowed to be parsed for a specific GraphQL route and that will be processed by the GraphQL for Gloo Gateway server. For example, let’s say we want to allow only queries that return the title, reviews, and ratings of our Bookinfo service:

query MyProductsForHome {
  productsForHome {
    title
    reviews {
      reviewer,	
      text
    }, 
    ratings {
      reviewer,
      numStars
    }
  }
}

The first thing we need to do is to calculate the SHA-256 hash value for a given query in the same way we did in our previous GraphQL blog post. Let’s start with defining our query as a single string without line breaks:

$ export QUERY="query MyProductsForHome { productsForHome { title reviews { reviewer, text }, ratings { reviewer, numStars } } }"

Next, we can calculate the SHA-256 hash value by using the ‘shasum’ command line utility:

$ export QUERY_SHA256=$(echo -n $QUERY | shasum -a 256 | head -c 64)

This will give us the following hash value:

$ echo $QUERY_SHA256
01f818a19df3fbe19940b7af2e0fa5adcf1884686bb4d3e289623d5fa1875231

We can add this hash value to our GraphQLAllowedQueryPolicy CR and apply it to our Kubernetes cluster to create the GraphQL safelist. Because the policy specifies the bookinfo-graphql route, the safelist is enforced on queries to our Bookinfo GraphQL service:

apiVersion: security.policy.gloo.solo.io/v2
kind: GraphQLAllowedQueryPolicy
metadata:
  name: bookinfo-allowed-queries
  namespace: bookinfo
spec:
  applyToRoutes:
  - route:
      labels:
        route: bookinfo-graphql
  config:
    allowedQueryHashes: 
      - 01f818a19df3fbe19940b7af2e0fa5adcf1884686bb4d3e289623d5fa1875231

Testing Our GraphQL Safelist

With our GraphQLAllowedQueryPolicy applied, we can now test our safelist. Let’s start by sending the query that we’ve configured in our safelist to the GraphQL service endpoint. We can use both a POST and a GET request to do this. In the following example, we will use the more common POST request. Note that this requires us to convert the GraphQL query into JSON format so that we can send it to our GraphQL service by using the cURL command. Your GraphQL client will most likely do this conversion for you.

First, we need to encode our GraphQL query to JSON format so that it can be sent to the GraphQL endpoint:

$ export QUERY_JSON={\"query\":\"$QUERY\"}

With our query in JSON format, we can now call the Bookinfo GraphQL API and format the output with the “jq” tool:

$ curl -H "Content-Type: application/json" -d $QUERY_JSON http://graphql.api.example.com/bookinfo-graphql | jq

{
  "data": {
    "productsForHome": [
      {
        "title": "The Comedy of Errors",
        "reviews": [
          {
            "reviewer": "Reviewer1",
            "text": "An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!"
          },
          {
            "reviewer": "Reviewer2",
            "text": "Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare."
          }
        ],
        "ratings": [
          {
            "reviewer": "Reviewer1",
            "numStars": 5
          },
          {
            "reviewer": "Reviewer2",
            "numStars": 4
          }
        ]
      }
    ]
  }
}

We can see that our query has been processed, and we have received the requested result.

Now let’s send a query that is not defined in our safelist, such as the following:

query MyProductsForHome {
  productsForHome {
    title
  }
}

When we convert that query to JSON format and send it to the GraphQL for Gloo Gateway server, we get the following response:

$ export QUERY="query MyProductsForHome { productsForHome { title } }"

$ export QUERY_JSON={\"query\":\"$QUERY\"}

$ curl -H "Content-Type: application/json" -d $QUERY_JSON http://graphql.api.example.com/bookinfo-graphql | jq
{
  "errors": [
    {
      "message": "hash ba7faf706579b441e281376ba5a87d5047e79eb52dcf6ac0eb34eb85ed53b053 not found in allowlist for query: 'query MyProductsForHome { productsForHome { title } }'"
    }
  ]
}

As you can see, the query is rejected because its SHA-256 hash is not defined in the safelist of our GraphQLAllowedQueryPolicy.

Gain More Query Control

GraphQL for Gloo Gateway is a powerful GraphQL server implemented directly in the Envoy-based Gloo Gateway proxy. The ability to define GraphQL APIs and configurations in cloud-native declarative fashion using Kubernetes-based APIs makes the platform extremely suitable for GitOps-based environments.

GraphQL query safelisting is a tool that allows the owners and administrators of GraphQL APIs to control which queries are allowed to be executed against their APIs. This gives API owners and administrators more control over both the security and performance of their GraphQL APIs, GraphQL resolvers, and back-end microservices and systems.

Learn more about Gloo Gateway features, including GraphQL.