从 curl 调用 GraphQL 端点意外失败
Posted
技术标签:
【中文标题】从 curl 调用 GraphQL 端点意外失败【英文标题】:Invoking GraphQL endpoints from curl failing unexpectedly 【发布时间】:2021-12-07 18:40:04 【问题描述】:多年来,我一直在使用 REST API(作为消费者和开发人员),并且刚刚开始第一次使用 GraphQL API,具体来说,BurpSuite's Enterprise GraphQL API。我喜欢它,但我肯定遗漏了一些关键概念。
我正在尝试访问他们的GetScan
端点:
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'
为了便于阅读,graphql 查询也是:
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"
<MY_API_KEY>
以上在我运行时具有实际价值(显然,我不能在此处发布)。与 URL 相同(我有一个 BurpSuite 的本地版本正在运行,例如 mybsee.example.com
)。
当我运行 curl 时,我得到以下输出:
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]
我无权访问服务器日志,因此我试图排除客户端的问题(我对GetScan
的调用不正确)。有人觉得有什么不对吗?我是否应该向查询中的任何字段注入值,例如id
或status
等?如果是这样,我如何(具体地)将查询更改为有效?我也不确定是否需要将"query"
JSON 字段名称附加到实际查询中。
感谢您在此提供的所有帮助。
更新
我确实意识到这不是一个完美可以回答的问题,因为不幸的是 BurpSuite API 是专有的,除非您购买产品或经历大量 rigamarole,否则您无法从他们那里获得 API 密钥获得免费试用许可证。
但更重要的是,我不是在这里寻找任何人来钓鱼,我希望有人可以教我如何钓鱼。实际上,除了这个之外,我还需要与更多 GraphQL 端点集成,但如果有人能告诉我构造一个查询的正确方法,我可以从那里获取。
【问题讨论】:
你错过了-H "Authorization:
结尾处的双引号。
感谢@chicks (+1) 这是我的复制粘贴错误;现在修好了!
我在您的查询中没有看到任何变量。你在哪里传递特定的 id?
(顺便说一句,将 graphql 查询格式化为多行正确缩进的文本会使其更易于阅读)。
不过,基本上:GetScan
需要提供一个 id
作为参数——ID!
中的 !
表示这是强制性的。
【参考方案1】:
最安全的方法是使用 jq
生成正确转义的 JSON,其中包含您的查询及其参数。
构建一个自动化的函数:
# 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"
...你可以使用这样的函数:
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=$(gqlQuery "$myUrl" "$getScanQuery" id="$scanIdToRetrieve")
【讨论】:
啊,好吧,我想我明白了!所以让我们看一下getScanQuery
变量的第一部分:GetScan ($id: ID!) scan(id: $id)...
/ 这是否翻译为“有一个GetScan
端点接受一个必需 参数$id
,即类型为“ID”(我假设 ID
是 GQL 领域中的一种类型)?然后在查询正文中引用 $id
的任何地方,从 variables
映射传入的值被替换?是这样吗有效吗?我也认为它的gqlQuery
无处不在,而不是golQuery
,对吧?再次感谢!
很正确golQuery
是一个错字,也很正确ID
是一种类型(类型可以定义为查询文本的一部分,当它们没有预定义时;我没有临时记住 ID
是否是预定义类型 - 如果不是,那么您可能需要在查询正文中包含它的定义。
我有点犹豫是否要确认“在正文中引用 $id 的所有位置”位的唯一原因是GetScan
查询的参数决定了在引用中填写的内容块,但这是一个没有太大区别的区别;您描述的方式通常非常接近:)
在graphql.org/learn/schema中查找,ID
确实是预定义类型。
顺便说一句,上面gqlQuery
的版本是一次性的;如果我正在构建一些用于生产用途的东西,我可能会在 case
语句的顶部添加类似 -X*) curlArgs+=( "$1%-X );;
的内容(在顶部定义 local -a curlArgs=( )
并在底部使用 curl "$curlArgs[@]"
之后)让调用者将额外的参数传递给curl
,而无需更改函数。【参考方案2】:
curl -k -i -H "Content-Type: application/json" -H "Authorization: Bearer <API_TOKEN>" -X POST -d " \"query\": \"$string\"" '<API_URL>'
您几乎做对了所有事情。只需将 HTTP 方法更改为 POST 而不是 GET。 GET 将尝试获取整个页面,而 POST 将与 GraphQL API 交互。
尽管如此,GraphQL serving over HTTP page 中声明 GET 方法也应该在某些限制下与查询一起使用。有关更多信息,请参阅链接。
还可以考虑访问导致我达到此决议的其他网页;Introduction to GraphQL on GitHubMaking GraphQL Requests using HTTP MethodsBurp Suite Enterprise GraphQL forum discussion with the same Error code of yours
【讨论】:
感谢 @Ido (+1),如果您不介意的话,还有两个后续问题:(1) 是 GraphQL 始终 POST,甚至查询?如果不是,你为什么建议我在这里使用 POST? (2) 我是否需要将变量值注入到我的查询中?如果是这样,我如何(具体来说,举个例子)实现这一点?再次感谢! @hotmeatballsoup,是的,它总是一个 POST,无论你是在做查询还是突变。 在示例中展示curl -k
(--insecure
) 其他人可能不假思索地效仿是一个真的坏主意。除此之外,OP 的 GraphQL 查询需要一个 id
变量,但他们没有传递一个。以上是关于从 curl 调用 GraphQL 端点意外失败的主要内容,如果未能解决你的问题,请参考以下文章
尝试从反应应用程序连接到 graphcool 中继 API 时出现此错误:模块构建失败:错误:没有有效的 GraphQL 端点