Home > Blockchain >  Invoking GraphQL endpoints from curl failing unexpectedly
Invoking GraphQL endpoints from curl failing unexpectedly

Time:10-22

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")
  • Related