為了檢查你在這些問題上的狀態(tài),你可以問問自己下面的“安全測(cè)試用例”一節(jié)中的問題。關(guān)于約束查詢執(zhí)行的深入討論,有一篇關(guān)于《如何使一個(gè) GraphQL API 更安全》的文章很不錯(cuò)。

https://leapgraph.com/graphql-api-security

3常見安全問題

既然我們已經(jīng)討論了基線配置,那我們可以進(jìn)一步討論三種常見的安全問題,這些問題在我們客戶的 GraphQL API 中經(jīng)常看到。

不恰當(dāng)?shù)臋?quán)限控制

實(shí)際上,我們?cè)?GraphQL(以及 REST/SOAP API)設(shè)計(jì)中,最常見的高風(fēng)險(xiǎn)問題都與不恰當(dāng)?shù)臋?quán)限控制有關(guān),但是由于對(duì)默認(rèn)解析器的過度依賴和缺乏一個(gè)集中授權(quán)層,這些問題在 GraphQL 中尤其普遍。讓我們來看看一些例子:?

執(zhí)行基于節(jié)點(diǎn)的訪問控制并利用授權(quán)層

每個(gè)節(jié)點(diǎn)都應(yīng)對(duì)它的數(shù)據(jù)和誰能訪問它的數(shù)據(jù)進(jìn)行負(fù)責(zé)。邊界檢查通常是無效的,因?yàn)橥ǔS卸鄠€(gè)邊界通向給定節(jié)點(diǎn)。(換句話說,僅僅因?yàn)槟憧梢栽L問一個(gè)列表并不意味著你就應(yīng)該能訪問列表中的每一個(gè)節(jié)點(diǎn)。)

此外,對(duì)默認(rèn)解析器的過度依賴和不安全的默認(rèn)字段可見性通常導(dǎo)致在開發(fā)過程中引入授權(quán)漏洞。你可以下載graphql-shield project來了解 GraphQL 的全功能授權(quán)層;它可以用作一個(gè)庫或者作為你自己設(shè)計(jì)的靈感。

最后,一定要研究你選擇的實(shí)現(xiàn)中授權(quán)異常是如何處理的。在一些案例中,異常可能泄露某個(gè)字段的存在,這可能是一個(gè)影響較大的信息泄露。?

使用可視化工具來幫助設(shè)計(jì)測(cè)試用例

有一個(gè)良好的規(guī)劃能讓你創(chuàng)建授權(quán)測(cè)試用例,并開發(fā)一個(gè)清晰的訪問控制系統(tǒng)。在開發(fā)測(cè)試用例時(shí),可以考慮使用如下的 GraphQL 可視化工具來識(shí)別敏感字段或節(jié)點(diǎn)。

目前,最流行的工具是 GraphQL Voyager:

此外,還可以試試 GraphQL Editor:

?經(jīng)常使用用戶 session 作為評(píng)估訪問的唯一信源

用戶 session 應(yīng)該是定義用戶的角色或功能的唯一用戶輸入。解析用戶 session 并依賴它作為評(píng)估訪問的唯一信源。

我們經(jīng)常看到 API 直接依賴數(shù)據(jù)庫中的對(duì)象查找(例如,為了安全起見,根據(jù)無序的 UUID 查詢),而不是聲明請(qǐng)求的 session 有權(quán)限訪問某個(gè)對(duì)象。僅僅依靠對(duì)象標(biāo)識(shí)符的保密性進(jìn)行授權(quán),只會(huì)創(chuàng)建更多機(jī)密來管理,從而給數(shù)據(jù)安全暴露更多漏洞。

不安全的輸入校驗(yàn)

在權(quán)限之后,輸入校驗(yàn)是我們?cè)?GraphQL API 看到的第二常見漏洞。不安全的輸入校驗(yàn)包括所有經(jīng)典的漏洞種類,例如 SQL 注入(SQLi)、跨站點(diǎn)腳本攻擊(XSS)、服務(wù)端請(qǐng)求偽造(SSRF)。

?使用自定義標(biāo)量進(jìn)行強(qiáng)輸入校驗(yàn)

GraphQL 提供了以下內(nèi)置標(biāo)量類型:String、Int、Float、Boolean 和 ID(序列化為一個(gè)字符串,接受數(shù)字或字符輸入)。然而,GraphQL 也支持你自定義標(biāo)量來創(chuàng)建自定義校驗(yàn)和序列化邏輯的類型(例如,DateTime類型)。強(qiáng)輸入和類型校驗(yàn)減少了來自用戶輸入的攻擊面,是保護(hù) API 的用戶輸入處理安全的第一道防線。

當(dāng)實(shí)現(xiàn)自定義標(biāo)量時(shí),考慮使用旨在定義通用自定義標(biāo)量的開源庫并進(jìn)行貢獻(xiàn)。這能幫助每個(gè)團(tuán)隊(duì)減少開發(fā)他們自己的校驗(yàn)邏輯所需的時(shí)間和精力,還可以幫助每個(gè)人避免重復(fù)相同錯(cuò)誤。下面是兩個(gè)現(xiàn)有的致力于創(chuàng)建共享自定義標(biāo)量庫的項(xiàng)目:

Urigo 的項(xiàng)目包含一個(gè)校驗(yàn)正則標(biāo)量的基礎(chǔ)模板,它簡(jiǎn)化了將現(xiàn)有的正則表達(dá)式從 REST API 到自定義標(biāo)量的轉(zhuǎn)變:

?避免自定義標(biāo)量封裝其它類型(JSON/XML)

避免創(chuàng)建復(fù)雜類型的自定義標(biāo)量,例如 JSON(例如graphql-type-json)。

復(fù)雜的自定義標(biāo)量會(huì)妨礙嵌套類型的正確校驗(yàn),還可能引入漏洞,例如 GraphQL 查詢注入或 NoSQL 注入。對(duì)于這些風(fēng)險(xiǎn),我們會(huì)在下一節(jié)進(jìn)行詳細(xì)討論。

其它轉(zhuǎn)換和緩存問題

大部分 GraphQL 實(shí)現(xiàn)是引入到現(xiàn)有的 REST 生態(tài)系統(tǒng)的。

在本節(jié),我們將檢查你在轉(zhuǎn)換過程中可能遇到的風(fēng)險(xiǎn)。GraphQL 和 REST 之間的轉(zhuǎn)換過程,結(jié)合緩存,它會(huì)導(dǎo)致各種不可預(yù)知的漏洞。

?REST 和 GraphQL 之間轉(zhuǎn)換時(shí)避免輸入校驗(yàn)問題

REST 轉(zhuǎn) GraphQL

假設(shè)我們引入了一個(gè)新的 GraphQL 后端服務(wù)來支持對(duì)一個(gè)現(xiàn)有的 REST API 網(wǎng)關(guān)的數(shù)據(jù)檢索。為了查詢 GraphQL 服務(wù),我們的開發(fā)者可能會(huì)嘗試將傳入的查詢參數(shù)插入到一個(gè)后端 GraphQL 請(qǐng)求中:

userUpdateQuery = `
mutation {
updateUser(
firstName: "${request['firstname']}",
lastName: "${request['lastname']}",
) {
User {
firstName
lastName
}
}
}
`;

傳統(tǒng)的 REST API 可能是弱類型的(GET/POST 參數(shù))或者強(qiáng)類型的(JSON/XML),這使得轉(zhuǎn)換成一個(gè)強(qiáng)類型 API 容易出錯(cuò)。例如,當(dāng)嘗試這樣轉(zhuǎn)換時(shí),有很多機(jī)會(huì)向查詢中注入額外的 JSON 語句。

為減少這些風(fēng)險(xiǎn),可以考慮使用持久化查詢。持久化查詢?cè)试S你將一個(gè)哈希值對(duì)應(yīng)于一個(gè)存儲(chǔ)的服務(wù)器端查詢及其輸入變量。這將安全插值委托給庫,限制了構(gòu)建請(qǐng)求時(shí)的查詢注入機(jī)會(huì)。

GraphQL 轉(zhuǎn) REST

作為我們遷移策略的一部分,假設(shè)我們?cè)诂F(xiàn)有的 REST API 前面放一個(gè) GraphQL 服務(wù)。

那么,針對(duì)我們的 GraphQL API 的服務(wù)器端解析函數(shù)可能會(huì)使用用戶提供的如下文件名參數(shù)來執(zhí)行訪問某個(gè)內(nèi)部 REST API 的內(nèi)部 GET 請(qǐng)求:

let myFile = await axios.get(https://api.product.int/file/${args.filename});

通過提交一個(gè)路徑遍歷負(fù)載作為參數(shù),攻擊者能控制外部的 API 請(qǐng)求來執(zhí)行惡意行為(例如,../user/setRoles?roles=[admin,user])。這只是會(huì)導(dǎo)致 SSRF 的不安全查詢構(gòu)建的一個(gè)例子;任何時(shí)候,外部請(qǐng)求中的用戶輸入都是有風(fēng)險(xiǎn)的。

這種轉(zhuǎn)換可能更有挑戰(zhàn)性,因?yàn)橛脩糨斎胄枰磺謇韮纱危涸?GraphQL 前端,對(duì)用于外部請(qǐng)求的查詢構(gòu)建中使用的數(shù)據(jù)進(jìn)行額外清理,然后在 REST 后臺(tái)服務(wù)中再次清理。

確保所有查詢參數(shù)都針對(duì)它們將放入的請(qǐng)求上下文進(jìn)行了清理(例如,路徑參數(shù)的 URI 語法和 JSON 信息的 JSON 語法)。盡可能依賴標(biāo)準(zhǔn)庫。?

在引入中間緩存時(shí)避免破壞授權(quán)

一些 GraphQL 實(shí)現(xiàn)會(huì)去除現(xiàn)有后端 REST 基礎(chǔ)設(shè)施的所有授權(quán)。這在為現(xiàn)有 REST API 創(chuàng)建一個(gè) GraphQL 網(wǎng)關(guān)時(shí)特別常見。然而,由于這會(huì)導(dǎo)致額外的延遲,所以常見的是在 GraphQL 服務(wù)器和 REST API 服務(wù)器之間引入中間緩存。然而,與轉(zhuǎn)換帶來的風(fēng)險(xiǎn)類似,這種方案也會(huì)導(dǎo)致問題。

如果授權(quán)過的響應(yīng)保存在緩存中,未經(jīng)授權(quán)的請(qǐng)求可能會(huì)不恰當(dāng)?shù)孬@取到緩存的內(nèi)容,而無需到后端 REST 服務(wù)器進(jìn)行授權(quán)檢查。由于授權(quán)邏輯位于中間緩存層后面,GraphQL 服務(wù)器需要處理緩存檢索邏輯來確保不會(huì)違反后端訪問控制。

4安全測(cè)試用例

既然我們已經(jīng)對(duì)遷移過程中可能遇到的問題和犯的錯(cuò)誤有了一個(gè)很好的理解,那么,我們可以定義一個(gè)測(cè)試用例列表:

introspection 在生產(chǎn)環(huán)境被禁用了嗎?

速率限制:

  1. 有查詢速率限制嗎?
  2. 有查詢深度限制嗎?
  3. 有響應(yīng)限制(例如,能否分頁)嗎?
  4. 有查詢復(fù)雜度限制嗎?

授權(quán):

  1. 查詢?cè)诠?jié)點(diǎn)層次有恰當(dāng)?shù)脑L問控制嗎?
  2. 所有數(shù)據(jù)的訪問路徑都保持相同的訪問控制嗎?
  3. 對(duì)于只有部分角色才能訪問的字段,這些訪問控制是強(qiáng)制的嗎?
  4. 不同的錯(cuò)誤響應(yīng)是否泄露了字段或節(jié)點(diǎn)的存在?
  5. 源代碼:授權(quán)檢查是否依賴單一信源(例如,用戶的 session)?;代碼對(duì)非白名單字段是否有回退拒絕規(guī)則?
  6. 輸入校驗(yàn):API 是否執(zhí)行強(qiáng)輸入校驗(yàn)(例如,有限制的整數(shù)值或者名稱的有限字符集);API 是否正確處理了 null 值;當(dāng)向輸入中注入常見的 SQL(例如,[‘]、[–]或[#])或 GraphQL(例如,JSON)語句時(shí),服務(wù)器端是否會(huì)報(bào)錯(cuò)?
  7. 轉(zhuǎn)換和緩存:GraphQL 到 REST:當(dāng)注入特定 URI 字符時(shí),REST API 會(huì)報(bào)錯(cuò)嗎?;REST 到 GraphQL:當(dāng)向前端 REST API 的查詢參數(shù)提交 JSON 語句時(shí),GraphQL 會(huì)報(bào)錯(cuò)嗎?;緩存:當(dāng)快速提交請(qǐng)求時(shí),會(huì)出現(xiàn)預(yù)期之外的現(xiàn)象嗎??jī)蓚€(gè)獨(dú)立的用戶賬戶快速提交請(qǐng)求又會(huì)怎么樣呢?

本文沒有討論以下日志測(cè)試用例,但也值得考慮:

5結(jié)論

我們?cè)诒疚挠懻摿烁鞣N常見的 GraphQL bug,但是在特定部署上下文中,它會(huì)出現(xiàn)更多的 bug;錯(cuò)誤配置的中間緩存層或者不安全的服務(wù)器端查詢構(gòu)建都會(huì)導(dǎo)致難以發(fā)現(xiàn)的 bug。

強(qiáng)大的安全性來自可靠的設(shè)計(jì)模式和易于閱讀的代碼,而且,最常見的缺陷仍來自不恰當(dāng)?shù)臉I(yè)務(wù)邏輯設(shè)計(jì)和授權(quán)控制。

此外,我們推薦閱讀 Shopify’s GraphQL design tutorial,它分享了他們的經(jīng)驗(yàn)教訓(xùn)以及如何利用第三方庫進(jìn)行安全配置和授權(quán),從而讓社區(qū)能共同受益。

https://engineering.shopify.com/blogs/engineering/unifying-graphql-design-patterns-best-practices-tutorials

原文鏈接:https://labs.bishopfox.com/tech-blog/design-considerations-for-secure-graphql-apis

文章轉(zhuǎn)自微信公眾號(hào)@InfoQ 架構(gòu)頭條

上一篇:

如何在以太坊上構(gòu)建GraphQL API

下一篇:

為你的 ASP. NET Core Web API 創(chuàng)建 Microsoft Power App
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)