GraphQL 是一種查詢語言,用於 API 設計和資料互動。它是由 Facebook 釋出的一款新型的資料查詢和操作語言,自 2012 年起在內部使用,自 2015 年起獲得開源許可。由於技術原因,越來越多的公司使用 GraphQL 並將其後端切換到這個新系統,但是,雖然這種查詢語言有很多優點,但隨著查詢變得更加複雜,它也有一些安全問題。資訊洩露、業務邏輯錯誤、IDOR 和不當存取控制是 GraphQL 端點上最常見的漏洞。
GraphQL 允許使用者端在一個請求中明確地指定需要的資料,並返回預期的結果,而不是像 RESTful API 那樣只能獲取預定義的資源。因此,GraphQL 簡化了使用者端與伺服器之間的通訊,提高了應用程式的效能和可延伸性。
與傳統的 RESTful API 不同,GraphQL 通過將資料查詢和資料修改分離開來,使得使用者端能夠更靈活地控制所需資料的粒度和型別,並且在多個資源之間建立關係。這樣,使用者端就可以很容易地實現高效的資料獲取和更新,而無需為每個特定的用例編寫特定的 API。
目前正在使用GraphQL的大型公司包括Facebook、PayPal、GitHub、Shopify、Twitter、Tesla、Hackerone等大型公司,可見GraphQL正在迅猛發展。
我們根據前文已經得知,GraphQL是一種用於API的查詢語言,它支援很多種查詢方式:
我們接下來主要介紹一下Query、Mutation、Subscription這三種。
Query是GraphQL中最常用的一種方式。它用於從伺服器端獲取資料,類似於RESTful API的GET方法。使用Query可以指定需要返回的欄位以及過濾條件。
例如,以下查詢會請求伺服器返回使用者ID為1的使用者名稱和電子郵件地址:
query {
user(id: 1) {
name
email
}
}
Mutation用於在伺服器端修改或新增資料,類似於RESTful API的POST、PUT和DELETE方法。Mutation支援向伺服器端提交一些引數,並根據引數來執行相應的操作。
例如,以下Mutation會將使用者ID為1的使用者名稱更改為"NewName":
mutation {
updateUser(id: 1, name: "NewName") {
id
name
email
}
}
Subscription是GraphQL中的一種高階特性,它允許使用者端通過WebSocket連線實時接收來自伺服器的資料更新。這對於需要實時通知的應用程式非常有用,如線上聊天、股票報價等。
例如,以下Subscription會訂閱一個名為newMessage的頻道,並在有新訊息時返回訊息內容:
subscription {
newMessage(channel: "chat") {
content
author
}
}
/graphql
/graphql-console
/graphql-devtools
/graphql-explorer
/graphql-playground
/graphql-playground-html
/graphql.php
/graphql/console
/graphql/graphql
/graphql/graphql-playground
/graphql/schema.json
/graphql/schema.xml
/graphql/schema.yaml
/graphql/v1
/HyperGraphQL
/je/graphql
/laravel-graphql-playground
/lol/graphql
/portal-graphql
/v1/api/graphql
/v1/graphql
/v1/graphql-explorer
/v1/graphql.php
/v1/graphql/console
/v1/graphql/schema.json
/v1/graphql/schema.xml
/v1/graphql/schema.yaml
/v2/api/graphql
/v2/graphql
/v2/graphql-explorer
/v2/graphql.php
/graph
/graphql/console/
/graphiql
/graphiql.php
內省攻擊本質上來說就是因為沒有修改預設設定導致攻擊者可以通過查詢 __schema
或者 __type
等系統級別的 Schema 來獲取伺服器上定義的所有型別、欄位、列舉等資訊。攻擊者可以利用這些資訊去了解伺服器的資料結構和業務邏輯,為下一步的攻擊行動做準備。
內省攻擊包含以下幾個方面:
__schema
查詢來獲取所有可用的 Schema 資訊,包括物件型別、標量型別、列舉型別、介面型別和輸入型別等。__type.fields
查詢來獲取所有欄位資訊,包括欄位名稱、型別和描述等。如下三段GraphQL 查詢語句本質上是相同的,都是用於獲取 GraphQL Schema 的後設資料資訊。它們的區別在於格式和編寫方式
{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}
{"query": "query IntrospectionQuery{__schema{queryType{name}mutationType{name}subscriptionType{name}types{...FullType}directives{name description locations args{...InputValue}}}}fragment FullType on __Type{kind name description fields(includeDeprecated:true){name description args{...InputValue}type{...TypeRef}isDeprecated deprecationReason}inputFields{...InputValue}interfaces{...TypeRef}enumValues(includeDeprecated:true){name description isDeprecated deprecationReason}possibleTypes{...TypeRef}}fragment InputValue on __InputValue{name description type{...TypeRef}defaultValue}fragment TypeRef on __Type{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name ofType{kind name}}}}}}}}"}
{"query":"query Query {\n __schema {\n queryType { name }\n mutationType { name }\n subscriptionType { name }\n types {\n ...FullType\n }\n directives {\n name\n description\n locations\n args {\n ...InputValue\n }\n }\n }\n }\n\n fragment FullType on __Type {\n kind\n name\n description\n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n }\n\n fragment InputValue on __InputValue {\n name\n description\n type { ...TypeRef }\n defaultValue\n }\n\n fragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n }"}
可以使用burp的外掛進行分析
之後就可以查詢其中一些漏洞了,比如修改ID引數查詢其他人員資訊
如果graphql內省模式被禁用,可以嘗試使用工具。
https://github.com/nikitastupin/clairvoyance
https://github.com/assetnote/batchql
我們首先請求一次該介面發現用時30481
然後新增一個systemUpdate引數再次請求,可以看到時間變成了80725。如果新增更多的systemUpdate引數即可導致攻擊發生。
https://blog.yeswehack.com/yeswerhackers/how-exploit-graphql-endpoint-bug-bounty/
https://zhuanlan.zhihu.com/p/390876937
注:技巧,可以瞭解 GraphQL 模式的功能。{"query":"query {\n system\n}","variables":null}
本文來自部落格園,作者:知冰,轉載請註明原文連結:https://www.cnblogs.com/zhibing/p/17350053.html