GraphQL滲透測試詳解

2023-04-24 18:01:00

GraphQL介紹

GraphQL概述

GraphQL 是一種查詢語言,用於 API 設計和資料互動。它是由 Facebook 釋出的一款新型的資料查詢和操作語言,自 2012 年起在內部使用,自 2015 年起獲得開源許可。由於技術原因,越來越多的公司使用 GraphQL 並將其後端切換到這個新系統,但是,雖然這種查詢語言有很多優點,但隨著查詢變得更加複雜,它也有一些安全問題。資訊洩露、業務邏輯錯誤、IDOR 和不當存取控制是 GraphQL 端點上最常見的漏洞。

GraphQL與傳統RESTful API的區別

GraphQL 允許使用者端在一個請求中明確地指定需要的資料,並返回預期的結果,而不是像 RESTful API 那樣只能獲取預定義的資源。因此,GraphQL 簡化了使用者端與伺服器之間的通訊,提高了應用程式的效能和可延伸性。

與傳統的 RESTful API 不同,GraphQL 通過將資料查詢和資料修改分離開來,使得使用者端能夠更靈活地控制所需資料的粒度和型別,並且在多個資源之間建立關係。這樣,使用者端就可以很容易地實現高效的資料獲取和更新,而無需為每個特定的用例編寫特定的 API。

GraphQL應用

目前正在使用GraphQL的大型公司包括Facebook、PayPal、GitHub、Shopify、Twitter、Tesla、Hackerone等大型公司,可見GraphQL正在迅猛發展。

GraphQL滲透測試前置知識

GraphQL查詢語言

我們根據前文已經得知,GraphQL是一種用於API的查詢語言,它支援很多種查詢方式:

  • Query
  • Mutation
  • Subscription
  • Input
  • Enum
  • Union
  • Interface

我們接下來主要介紹一下Query、Mutation、Subscription這三種。

Query

Query是GraphQL中最常用的一種方式。它用於從伺服器端獲取資料,類似於RESTful API的GET方法。使用Query可以指定需要返回的欄位以及過濾條件。

例如,以下查詢會請求伺服器返回使用者ID為1的使用者名稱和電子郵件地址:

query {
  user(id: 1) {
    name
    email
  }
}

Mutation

Mutation用於在伺服器端修改或新增資料,類似於RESTful API的POST、PUT和DELETE方法。Mutation支援向伺服器端提交一些引數,並根據引數來執行相應的操作。

例如,以下Mutation會將使用者ID為1的使用者名稱更改為"NewName":

mutation {
  updateUser(id: 1, name: "NewName") {
    id
    name
    email
  }
}

Subscription

Subscription是GraphQL中的一種高階特性,它允許使用者端通過WebSocket連線實時接收來自伺服器的資料更新。這對於需要實時通知的應用程式非常有用,如線上聊天、股票報價等。

例如,以下Subscription會訂閱一個名為newMessage的頻道,並在有新訊息時返回訊息內容:

subscription {
  newMessage(channel: "chat") {
    content
    author
  }
}

GraphQL滲透測試方法和流程

  • 滲透測試準備工作
  • 滲透測試步驟
    • 列舉 GraphQL Schema
    • 查詢漏洞
    • 注入漏洞
    • 認證和授權漏洞

常見的GraphQL路徑

/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

GraphQL 滲透測試實戰案例分析

消耗伺服器資源攻擊案例

我們首先請求一次該介面發現用時30481

然後新增一個systemUpdate引數再次請求,可以看到時間變成了80725。如果新增更多的systemUpdate引數即可導致攻擊發生。

SSRF漏洞案例

防禦和修復 GraphQL 漏洞的建議

  1. 限制查詢語句的深度和複雜度:GraphQL 支援巢狀查詢和引數化查詢,這使得攻擊者可以構造非常複雜的查詢來增加伺服器的負載,甚至可能導致拒絕服務攻擊。為了防範此類攻擊,可以對查詢語句進行深度和複雜度限制,以確保每個查詢不會佔用過多的資源。
  2. 限制查詢的存取許可權:GraphQL API 應該只允許授權存取,而不是任何人都可以存取。可以通過身份驗證、IP 白名單、API 金鑰等方式來限制查詢的存取許可權,從而避免惡意查詢和攻擊。
  3. 限制查詢返回的欄位和資料量:攻擊者可以利用查詢返回大量的資料來耗盡伺服器資源或者獲取敏感資訊。為了防止這種情況發生,應該限制每個查詢返回的欄位和資料量,並對某些敏感欄位進行隱藏或者過濾處理。
  4. 檢查輸入引數的合法性:GraphQL 允許使用者端自由傳遞引數,這也使得攻擊者可以利用引數注入漏洞來攻擊系統。因此,在伺服器端需要對輸入引數進行嚴格校驗和過濾,避免惡意引數的注入和攻擊。
  5. 關閉內省查詢:GraphQL 內省機制被用來獲取伺服器上定義的所有型別、欄位、列舉等資訊。攻擊者可以利用這些資訊瞭解伺服器的資料結構和業務邏輯,從而進行進一步攻擊。為了防範此類攻擊,應該關閉或限制內省查詢功能。

參考

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}