I've been using REST APIs (both as a consumer and a developer of) for many years and am just starting to work with a GraphQL API for the first time, specifically, BurpSuite's Enterprise GraphQL API. I like it but I'm definitely missing a few critical concepts.
I am trying to hit their GetScan
endpoint:
curl -k -i -H "Content-Type: application/json" -H "Authorization: <MY_API_KEY>" -X GET -d '{ "query": "query GetScan ($id: ID!) { scan(id: $id) { id status agent { id name } site_application_logins { login_credentials { label username } recorded_logins { label } } audit_items { id issue_counts { total } number_of_requests } scan_configurations { id name } } }"}' 'https://mybsee.example.com/graphql/v1'
For easier reading, that graphql query is also:
query GetScan ($id: ID!) {
scan(id: $id) {
id status
agent { id name }
site_application_logins {
login_credentials { label username }
recorded_logins { label }
}
audit_items {
id
issue_counts { total }
number_of_requests
}
scan_configurations { id name }
}
},
variables {
$agent: "Firefox"
}
Above <MY_API_KEY>
has a real value when I run it (I can't post it here, obviously). Same with the URL (I have an on-premise version of BurpSuite running off, say, mybsee.example.com
).
When I run that curl, I get the following output:
About to execute: query GetScan ($id: ID!) { scan(id: $id) { id status agent { id name } site_application_logins { login_credentials { label username } recorded_logins { label } } audit_items { id issue_counts { total } number_of_requests } scan_configurations { id name } } }
HTTP/2 200
date: Wed, 20 Oct 2021 23:33:50 GMT
x-frame-options: DENY
<lots of response headers omitted>
{"errors":[{"message":"Unexpected exception occurred. Check logs for more details.","extensions":{"code":77}}]}
I don't have access to the server logs, so I'm trying to rule out an issue on the client-side (bad call to GetScan
on my part). Anything look wrong to anybody? Should I be injecting values to any of the fields in the query, such as id
or status
, etc.? If so, how (specifically) could I change the query to be valid? I'm also not sure if I need to append a "query"
JSON field name into the actual query or not.
Thanks for any and all help here.
Update
I do realize that this is not a perfectly answerable problem, because the BurpSuite API is unfortunately proprietary and you cannot obtain an API key from them unless you purchase the product or go through a lot of rigamarole to get a free trial license.
But more importantly, I'm not looking for anyone to fish for me here, I'm hoping someone can teach me how to fish. In reality I need to integrate with a lot more GraphQL endpoints besides this one, but if someone can show me the proper way to construct one query, I can take it from there.
CodePudding user response:
curl -k -i -H "Content-Type: application/json" -H "Authorization: Bearer <API_TOKEN>" -X POST -d "{ \"query\": \"$string\"}" '<API_URL>'
You did almost everything right. Just Change the HTTP Method to POST instead of GET. GET will try to fetch the whole page, POST on the other hand will interact with the GraphQL API.
Nevertheless stated in the GraphQL serving over HTTP page that GET Method should also work with queries under certain limtations. Refer the links for more Information.
Also consider visting other Webpages which lead me to this resolution;
Introduction to GraphQL on GitHub
Making GraphQL Requests using HTTP Methods
Burp Suite Enterprise GraphQL forum discussion with the same Error code of yours
CodePudding user response:
The safest way to do this is to use jq
to generate correctly-escaped JSON with both your query and its parameters.
Building a function to automate that:
# usage: gqlQuery http://ENDPOINT/graphql "$query" arg1=val1 arg2=val2 ...
gqlQuery() {
local endpoint query postBody
local -a jqArgs=( )
endpoint=$1; shift || return
query=$1; shift || return
while (( $# )); do
case $1 in
# the variable name "query" is used for passing in, well, the query
query=*) echo "ERROR: variable name query is reserved" >&2; return 1;;
# 'foo=JSON:["bar", "baz"]' passes ["bar", "baz"] as a list, not a string
*=JSON:*) jqArgs =( --argjson "${1%%=*}" "${1#*=}" ) ;;
# without JSON:, everything gets passed as a string to the child
*=*) jqArgs =( --arg "${1%%=*}" "${1#*=}" ) ;;
# arguments without a = are not recognized
*) echo "ERROR: Argument $1 not well-formed" >&2; return 1;;
esac
shift
done
postBody=$(jq -nc \
--arg query "$query" \
"${jqArgs[@]}" \
'{ "query": $query, "variables": ($ARGS.named | del(.query)) }'
) || return
curl --fail -XPOST \
-H 'Content-Type: application/json' \
-d "$postBody" "$endpoint"
}
...you might use such a function as:
getScanQuery='query GetScan ($id: ID!) { scan(id: $id) { id status agent { id name } site_application_logins { login_credentials { label username } recorded_logins { label } } audit_items { id issue_counts { total } number_of_requests } scan_configurations { id name } } }'
myUrl=https://mybsee.example.com/graphql/v1
scanIdToRetrieve=1000 # replace with whatever is appropriate
result=$(golQuery "$myUrl" "$getScanQuery" id="$scanIdToRetrieve")