GraphQL API Support - Introduction

As of HawkScan v.0.6.6, StackHawk now provides GraphQL API scanning support.

Enabling this feature allows HawkScan to perform introspection of your app to generate routes based on available GraphQL operations. If enabled, the scanner works to enumerate all output types, input types and input parameters for the available Query and Mutation operations found from introspection.

Please see the configuration section for more details.

Operation Generation

Functional Overview

  1. HawkScan initially introspects the GraphQL schema endpoint for available types and operations.
  2. Once the output and input types have been enumerated, HawkScan generates new requests based on these values and combines the requirements into requests using additional variables and populates child fields and dependencies wherever possible.
  3. Initial values provide each set of test input variables with data and operations begin populating the spider with requests.
  4. HawkScan uses these initial requests to feed discovered routes back into the active scanner for auditing.
  5. Requests use the POST HTTP method by default, but GET requests are also supported per the GraphQL specification.

GraphQL Configuration

At a minimum, HawkScan requires app.graphqlConf.enabled be set to true in stackhawk.yaml to enable support. Provide a relative path to the introspection endpoint if necessary.

Additional parameters can be found under the app.graphqlConf section of the stackhawk.yml. Settings include recursion depth, max URI length for GET requests, rate limiting on introspection and setting the target operation type.

By default, the spider generates operation requests for both Query and Mutation types. This behavior can be altered to only one or the other with the .operation parameter.

The following is an example of a base configuration for scanning GraphQL:

Example:

stackhawk.yml

app:
  host: http://localhost:3000
  graphqlConf:
    enabled: true
    schemaPath: '/graphql'
    operation: ALL
    maxDepth: 3

Note: Take note of other configured scanning features such as *OpenAPI* or *AJAX Spider* support as this may delay scan times and completion in larger environments.

Example GraphQL Schema Introspection

More information on GraphQL fields, types, variables and operations can be found in the following series of documents:

HawkScan expects a well-formed GraphQL schema definition which conforms to the GraphQL specification.

A simple example:

schema

{
  "data": {
    "__schema": {
      "queryType": {
        "name": "Query"
      },
      "mutationType": {
        "name": "Mutation"
      },
      "subscriptionType": null,
      "types": [
        {
          "kind": "OBJECT",
          "name": "Query",
          "description": null,
          "fields": [
            {
              "name": "post",
              "description": null,
              "args": [
                {
                  "name": "where",
                  "description": null,
                  "type": {
                    "kind": "NON_NULL",
                    "name": null,
                    "ofType": {
                      "kind": "INPUT_OBJECT",
                      "name": "PostWhereUniqueInput",
                      "ofType": null
                    }
                  },
                  "defaultValue": null
                }
              ],
              "type": {
                "kind": "OBJECT",
                "name": "Post",
                "ofType": null
              },
              "isDeprecated": false,
              "deprecationReason": null
            }
		  ]
	    }
	  ]
	}
  }
}

HawkScan generated requests

*HawkScan* provides support for both POST and GET requests.

The following is an example POST request.

POST http://localhost:4000 HTTP/1.1
User-Agent: HawkScan/2.0; StackHawk, Inc. (https://www.stackhawk.com)
Pragma: no-cache
Cache-Control: no-cache
Content-Length: 296
Accept: application/json
Content-Type: application/json
Host: localhost:4000

{
  "query": "query filterPosts($searchString:String ) { filterPosts(searchString:$searchString) { id } }",
  "variables": {
    "searchString": "KaaaKaww!"
  }
}

Following is an example GET request.

http://localhost:4000?query=filterPosts($searchString:String%20)%20%7B%20filterPosts(searchString:$searchString)%20%7B%20id%20%7D%20%7D&variable

Query and Mutation operations are both enumerated by default. This behavior can be altered to allow targeting either Query or Mutation operations only. See .graphqlConf for more info.

Batching Operations

Batch request operations allows HawkScan to combine top level output types into a single request.

Using graphql-apollo-server in the Prisma scanner test project as an example, operations generated without batching enabled appear as follows:

{"query":"mutation publish($id:Int ) { publish(id:$id) { id } }","variables":{"id":1}}
{"query":"mutation publish($id:Int ) { publish(id:$id) { title } }","variables":{"id":1}}
{"query":"mutation publish($id:Int ) { publish(id:$id) { content } }","variables":{"id":1}}
{"query":"mutation publish($id:Int ) { publish(id:$id) { published } }","variables":{"id":1}}
{"query":"mutation publish($id:Int ) { publish(id:$id) { author    } }","variables":{"id":1}}
{"query":"mutation publish($id:Int ) { publish(id:$id) { authorId } }","variables":{"id":1}}

With batching enabled, these requests are joined into a single operation:

{"query":"mutation publish($id:Int ) { publish(id:$id) { id title content published author authorId } }","variables":{"id":1}}

Note that depending on recursion depth, this may or may not provide all required child fields for a type.