Table of Contents

Now we know what our Schema looks like, and what queries and mutations we can do. Now let's learn how to craft out queries from the  information we got from introspection which we discussed in Part 1 of this blog.

GraphQL Pentest Series

1️⃣ GraphQL Pentesting for Dummies! Part-1

2️⃣ GraphQL Pentesting for Dummies! Part-2

3️⃣ GraphQL Pentesting for Dummies! Part-3 [coming soon]

GraphQL Operations

Query: fetching data using specifically defined query operations.
Mutations: for modifying any data (creating, updating, or deleting) in a database using operations.
Subscriptions: for receiving real-time messages from the back end.

While we use queries to fetch data, we use mutations to modify server-side data.

If queries are the GraphQL equivalent to GET calls in REST, then mutations represent the state-changing methods in REST (like DELETE, PUT, PATCH, etc).

For learning purposes, we will be using the publicly available Fruit Shop Graphql

https://www.predic8.de/fruit-shop-graphql?query=

First thing first, let's check if introspection queries are enabled to get the landscape of our Graphql API.

{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}

Let's visualize it using any of the methods we discussed earlier. I am using my favorites graphql voyager

1. Queries

1.1. Return all Objects of a Type

The query below returns a list of products with their names. You can use the methods categories , customers , vendors and orders as well.

Fields: At its simplest, GraphQL is about asking for specific fields on objects. The field name returns a String type, in this case the name of the products in the fruit shop.

To return a list of products with their names. We check the schema for the product and see what all fields can be queried from products.

We can see there are id, name, price, categoryID and vendorID.

Let's craft a query to return a list of products with their names. It will look something like this

query{products {
  name
}
}

1.2. Searching by ID

Let's craft a Query returning product with id 7, we can use id as an argument. You can use name, price, categoryID and vendorID anyother subfeilds as arguments.

Arguments: An argument is a value you provide for a particular field in your query. The schema defines the arguments that each of your fields accepts. In this example, we used the argument id to get the product with argument value "1"

{
  products(id: "1") {
    name
  }
}

why the value of id is in quotes? because it's a string. refer to the schema

1.3. Selection of Subfields

The returned objects are JSON-objects that can be quite complex. The fields of an object can itself be a JSON-object with fields of its own and so on. In a query you can specify which of these fields and subfields you want to return. If a field has subfields you have to make a selection of these subfields in order for the query to work.

As we saw earlier there are other subfields other than name in products, for example, let's check price of id=2.

{
 products(id: "2") {
    name
    price
  }
}

Let's craft a query returning category and vendor of a product

{
  products(id: "2") {
    name
    price
    category {
      name
    }
  }
}

Let's craft a query returning category and vendor of a product

{
  products(id: "2") {
    name
    price
    category {
      name
    }
    vendor {
      name
    }
  }
}

Besides the id you can give query methods additional arguments. The methods then only return objects which have in their fields values corresponding to the values of those arguments.

1.4. Filtering Fields

Query returning products with price=1.1 and category=1

{
  products(price: 1.1, categoryID: 1) {
    name
    price
    category {
      name
    }
    vendor {
      name
    }
  }
}

1.5. Multiple Levels of nested Subfields

By selecting subfields you can build queries that have deep levels of subfield nesting. You can even include circles of subfields.

Query with nesting categories -> products -> vendor -> products

{
  categories(id: "1") {
    name
    products {
      name
      vendor {
        products {
          name
        }
      }
    }
  }					
}

Some more terms!

Aliases

We can't directly query for the same field with different arguments. That's why you need aliases - they let you rename the result of a field to anything you want.

{
  Produc1:products(id:"1") {
    name
  }
  Produc2:products(id:"2") {
    name
  }
}

Operation name

Until now, we have been using a shortened syntax that excludes both the query keyword and the query name. However, in production applications, it is beneficial to include these elements to increase the clarity of the code.

Here’s an example that includes the keyword query as operation type and productNameandPrice as operation name :

query productNameandPrice {
  products(id: "1") {
    name
    price
  }
}

Variables

So far, we have been writing all of our arguments inside the query string. In GraphQL, you can use variables to reuse the same query/mutations written by the client, with different arguments.

Variables can be declared after the query or mutation and are passed like arguments to a function and begin with $.

query productNameandPrice($testid : String!) {
  products(id:$testid){
    name
  }
}

Query Variables

{
  "testid": 1
}

There are three steps that need to be done when you start using variables in your query or mutation:

  1. Replace the static value in the query with $variableName
  2. Declare $variableName as one of the variables accepted by the query
  3. Pass variableName: value in the separate, transport-specific (usually JSON) variables dictionary

Default variables: If default values are specified for all variables, you can execute the query without providing any variables. If any variables are passed as part of the variables dictionary, they will override the defaults.

query productNameandPrice($testid : String = "2") {
  products(id:$testid){
    name
  }
}

More you can read from here

Queries and Mutations | GraphQL
A query language for your API — GraphQL provides a complete description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.

2. Mutations

Mutations allow you to modify server-side data, and it also returns an object based on the operation performed. It can be used to insert, update, or delete data.

How do we know what all actions we can perform? Graphql Voyager is here to help

Select Mutation

Now all the available actions are visible to us.

2.1. Add Mutations

You can add new objects of the main types with the corresponding add mutations. If you do this you have to provide all attributes for the object.

Query adding a category products 5, 6, 7

mutation addcatagory{
  addCategory(id: 1, name:"Green Fruits", products:[5,6,7]){
    name
    products {
      name
    }
  }
}

Let's see if it got updated

query{
  categories {
    id
    name
    products{
      name
      id
    }
  }
}

2.2. Update Mutations

Changes an object of a type specified by the provided id. You can change all or just certain attributes depending on which attributes you provide. The state of the object after the modification is returned as well.

Query changing name und products of the category with id 1

mutation{
  updateCategory(id: 1, name: "Healthy Fruits", products: [7]){
    name
    products{
      name
    }
  }
}

Let's see if it got updated

2.3. Delete Mutations

Deletes object with provided id. The deleted object gets returned.

Let's delete category 1

mutation {
  deleteCategory(id: 1) {
    name
 }
}

Let's see if it actually got deleted

Yep! it got deleted.

Resources

📢
Part 3 of the blog will be coming soon!

I still remember the first GraphQL pentest I did, where I manually crafted the queries and thought there might be better way! Yes there is and we will discuss that in our next blog.


Put your brain to use

Well done if you have come here! Now you must be more confident in query and mutation. Let's put what you learn to the test.

I challenge you!

  1. Navigate to the repo graphql-apis and take any publically available GraphQL API
  2. Check if the Introspection Query is enabled or not?
  3. If yes, then visualize the GraphQL Schema with your favorite method.
  4. Start crafting your own Query and Mutations.
  5. Share this blog with your friends! 
Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Anugrah SR | #HackLearnDaily.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.