Intro
In the last post, we touched on the topic of GraphQL security. As a reminder, GraphQL is a popular alternative to REST APIs.
A single article can not encapsulate all the things one wants to know about such an interesting technology. This installment of the series will look at the first step of analyzing how well GraphQL is protected, specifically securing the GraphQL schema by disabling introspection query which is enabled by default.
What is GraphQL Schema?
“The schema is one of the most important concepts when working with a GraphQL API. It specifies the capabilities of the API and defines how clients can request the data. It is often seen as a contract between the server and the client.
Generally, a schema is simply a collection of GraphQL types.”
Link: https://www.howtographql.com/basics/2-core-concepts/
Thanks to the introspection mechanism, by default any unauthenticated user can analyze GrapQL the schema. Introspection allows us to get information about all the Requests, Mutations, Subscriptions, and Data Types and all other things that are made available to the clients making requests. This information is easily available by requesting ___schema meta-field, which, according to the specification, is always available to the query of the “root” type.
Why
We do need to understand the details of the GraphQL schema in the first place. The reason is in the need to think like a potential attacker. The information about Queries, Mutations, Types and so on would give an attacker many opportunities to find vulnerabilities and errors in processing in a specific GraphQL implementation.
Putting it out in the open is the same as making the application source code widely available and expecting attackers wouldn’t take advantage of find errors in it.
Specific issues that may become an application downfall are described in more details in the first installment of this series about GraphQL security. (https://lab.wallarm.com/securing-and-attacking-graphql-part-1-overview/ )
How
GraphQL introspection
Below are some examples of restricting access to the GraphQL introspection within some of the popular frameworks and programming languages.
PHP
use GraphQL\GraphQL;
use GraphQL\Validator\Rules\DisableIntrospection;
use GraphQL\Validator\DocumentValidator;
DocumentValidator::addRule(new DisableIntrospection());
Link: https://webonyx.github.io/graphql-php/security/#disabling-introspection
Ruby
class MySchema < GraphQL::Schema disable_introspection_entry_points if Rails.env.production? end
NodeJS
app.use('/graphql', graphqlHTTP({ schema: MyGraphQLSchema, + validationRules: [NoIntrospection] }));
Link: https://www.npmjs.com/package/graphql-disable-introspection
Python
In Python, GraphQL API implementation is based on a popular Graphene library. At the time of writing of this post, out-of-the-box Graphere does not offer disabling introspection (Link: https://github.com/graphql-python/graphene/issues/907). The authors recommend using MiddleWare class to disable requests to meta-property _schema. See the example below:
class HideIntrospectMiddleware: """ This middleware should use for production mode. This class hide the introspection. """ def resolve(self, next, root, info, **args): if info.field_name == '__schema': return None return next(root, info, **args)
In addition, we should remember that introspection is available not just for the schema, but also for specific properties of the GraphQL entity such as:
__Schema __Directive __DirectiveLocation __Type __Field __InputValue __EnumValue __TypeKind
This means the code example above would only protect from the simplistic analysis attempts. To really secure the implementation, a filtering mechanism for the inputs should be implemented. Such a mechanism would need to prohibit requests to any entities starting with _ in the production environment.
Java
One of the most popular GraphQL implementations in Java is https://www.graphql-java.com/.
To disable all types of introspection in this implementation, use the example below.
GraphQLSchema schema = GraphQLSchema.newSchema() .query(StarWarsSchema.queryType) .fieldVisibility( NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY ) .build();
Link: https://www.graphql-java.com/documentation/v11/execution/
As you can see from the above examples, many frameworks allow you to disable the introspection natively. But if they don’t, there is always a universal solution of filtering the input before it gets to the framework.
In the next article, we will discuss additional ways of how attackers can retrieve schema information from GraphQL even when the introspection query is disabled.
As you can see, securing GraphQL even in terms of protecting the schemas is not an easy job. That’s why an external application security layer like Wallarm is critical to a successful deployment of GraphQL in production.
Stay tuned.