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

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

3常見安全問題

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

不恰當?shù)臋嘞蘅刂?/strong>

實際上,我們在 GraphQL(以及 REST/SOAP API)設計中,最常見的高風險問題都與不恰當?shù)臋嘞蘅刂朴嘘P,但是由于對默認解析器的過度依賴和缺乏一個集中授權層,這些問題在 GraphQL 中尤其普遍。讓我們來看看一些例子:?

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

每個節(jié)點都應對它的數(shù)據(jù)和誰能訪問它的數(shù)據(jù)進行負責。邊界檢查通常是無效的,因為通常有多個邊界通向給定節(jié)點。(換句話說,僅僅因為你可以訪問一個列表并不意味著你就應該能訪問列表中的每一個節(jié)點。)

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

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

使用可視化工具來幫助設計測試用例

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

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

此外,還可以試試 GraphQL Editor:

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

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

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

不安全的輸入校驗

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

?使用自定義標量進行強輸入校驗

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

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

Urigo 的項目包含一個校驗正則標量的基礎模板,它簡化了將現(xiàn)有的正則表達式從 REST API 到自定義標量的轉變:

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

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

復雜的自定義標量會妨礙嵌套類型的正確校驗,還可能引入漏洞,例如 GraphQL 查詢注入或 NoSQL 注入。對于這些風險,我們會在下一節(jié)進行詳細討論。

其它轉換和緩存問題

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

在本節(jié),我們將檢查你在轉換過程中可能遇到的風險。GraphQL 和 REST 之間的轉換過程,結合緩存,它會導致各種不可預知的漏洞。

?REST 和 GraphQL 之間轉換時避免輸入校驗問題

REST 轉 GraphQL

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

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

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

為減少這些風險,可以考慮使用持久化查詢。持久化查詢允許你將一個哈希值對應于一個存儲的服務器端查詢及其輸入變量。這將安全插值委托給庫,限制了構建請求時的查詢注入機會。

GraphQL 轉 REST

作為我們遷移策略的一部分,假設我們在現(xiàn)有的 REST API 前面放一個 GraphQL 服務。

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

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

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

這種轉換可能更有挑戰(zhàn)性,因為用戶輸入需要被清理兩次:在 GraphQL 前端,對用于外部請求的查詢構建中使用的數(shù)據(jù)進行額外清理,然后在 REST 后臺服務中再次清理。

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

在引入中間緩存時避免破壞授權

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

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

4安全測試用例

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

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

速率限制:

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

授權:

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

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

5結論

我們在本文討論了各種常見的 GraphQL bug,但是在特定部署上下文中,它會出現(xiàn)更多的 bug;錯誤配置的中間緩存層或者不安全的服務器端查詢構建都會導致難以發(fā)現(xiàn)的 bug。

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

此外,我們推薦閱讀 Shopify’s GraphQL design tutorial,它分享了他們的經(jīng)驗教訓以及如何利用第三方庫進行安全配置和授權,從而讓社區(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

文章轉自微信公眾號@InfoQ 架構頭條

#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

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

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

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

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費