GraphQL Support
HawkScan is pioneering application security testing for GraphQL APIs.
Hawkscan will perform introspection of a GraphQL app to generate routes based on available operations. The scanner can be configured to enumerate all available types and input parameters for Query
and Mutation
together, or for each individual type separately.
See GraphQL configuration settings for more details.
How It Works
To perform application security testing against a GraphQL API, Hawkscan runs the following processes:
- The scanner initially introspects the GraphQL schema endpoint for available types and operations.
- After collecting input types and arguments, HawkScan generates requests and populates arguments with test values to begin spidering the GraphQL API in preparation for attack.
- Requests sent as
POST
by default, while usingGET
requests is a configurable option. See requestMethod in the GraphQL configurations for more info - The active scanner goes to work on each route discovered by the spider.
Note: If your stackhawk.yml
file has other features enabled such as OpenAPI or AJAX Spider you may experience longer
scan completion times in larger environments.
GraphQL Configuration
To get started, HawkScan requires app.graphqlConf.enabled
set to true
in stackhawk.yml
.
You would want a stackhawk.yml
configuration like this.
stackhawk.yml
app:
host: http://localhost:3000
graphqlConf:
enabled: true
schemaPath: /relative/uri/path/graphql
filePath: relative/path/to/gql/schema.json
operation: MUTATION
requestMethod: GET
app.graphqlConf.schemaPath
Provide a relative path to the introspection endpoint.
This should also be the GraphQL API endpoint for sending queries.
If no schema path has been provided, the scanner will default to look for it at /graphql
app.graphqlConf.filePath
It is possible to provide the GraphQL schema as a JSON file. Provide the relative path to a JSON formatted GraphQL schema. This path is relative to the HawkScan Docker context which is the current working directory, by default.
A schemaPath
will still need to be provided if the GraphQL endpoint is not at /graphql
Note: HawkScan requires either a schemaPath
-OR- ‘filePath
to acquire the introspection endpoint.
app.graphqlConf.uriMaxLength
Some queries can exceed recommended lengths when using the GET
request method. Max URI length for GET
requests will truncate long URIs and may result in misfired requests.
app.graphqlConf.operation
By default, the spider generates operation requests for both Query
and Mutation
types. Use this option to target
one or the other individually.
More Configuration Support
For more detailed configuration options, check out the GraphQL Scanner Parameters
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.
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!"
}
}
GET
request:
http://localhost:4000?query=filterPosts($searchString:String%20)%20%7B%20filterPosts(searchString:$searchString)%20%7B%20id%20%7D%20%7D&variable