API查詢語言GraphQL的優秀安全實踐
譯文【51CTO.com快譯】作為最為流行的查詢語言之一,GraphQL雖然能夠支持創建靈活的API,但是它也容易放過、甚至給應用程序服務器帶來各種惡意的查詢。一些常見的GraphQL漏洞往往會在一致性評估和缺陷緩解等方面埋下各種安全隱患。在本文中,我們將深入和您探討GraphQL的各種常見漏洞,以及降低此類風險的優秀實踐。
什么是GraphQL?
作為一種服務器端運行時(runtime)的API查詢語言,GraphQL能夠優先返回客戶端請求的數據。該語言不但能夠讓API變得輕巧、靈活,而且對于開發人員十分友好且方便他們進行快速開發。而作為REST API框架的替代方案,GraphQL允許開發團隊在單個接口的調用中,創建可訪問來自多個數據源的請求。該語言可以被部署到集成開發環境(IDE)中,并提供描述用戶該如何請求數據的語法??梢哉f,GraphQL既提供了一個可預測運行的框架,又允許開發人員自行選擇構建API的方法。
GraphQL的常見安全問答
API攻擊普遍嗎?
隨著API普遍被使用,針對它的攻擊嘗試在數量上也在持續增加。這些攻擊通常依賴于通過應用程序的編程接口,去自動化執行各種惡意操作。根據Wallarm.com的一份統計報告,截至2019年,惡意自動化攻擊主機、及其網絡已占互聯網的20%。這使得保護API成為應用程序安全措施的一個關鍵環節。
是否有簡化GraphQL安全性的工具?
目前,業界有多種開源的項目,可以簡化GraphQL API的創建和管理。其中包括:Apollo client、Offix、Graphback和 OpenAPI-to-GraphQL。
GraphQL如何處理身份驗證和授權?
由于GraphQL是一種服務器端運行時查詢語言,因此它并不處理授權的邏輯。不過,該平臺允許開發人員,在向客戶端公開API之前,在業務邏輯層中實施身份驗證和授權的檢查。
GraphQL的具體安全性問題
憑借著其豐富的平臺功能,以及能夠簡化API查詢的創建過程,GraphQL已被譽為現代應用開發技術棧的關鍵組件。而為了協助企業減少GraphQL API的攻擊面,我們可以通過如下方面來管控GraphQL平臺的固有安全問題:
自定義標量的驗證不足
在使用GraphQL時,原始數據往往是由標量類型(scalar type)表示的。GraphQL API通常支持五種基本的標量數據類型,即:Int、Float、Boolean、ID和String。雖然這個基本集合對于簡單的API來說已經足夠了,但是GraphQL也允許開發人員針對特殊的原始數據API類型需求,自行創建標量類型。當然,開發人員需要針對此類配置,額外地增加用戶輸入的驗證、以及清理的過程。相反,如果未能實現此類功能,則會危及到GraphQL標量類型的安全性。
REST代理充當API攻擊媒介
在調整現有的API以供GraphQL客戶端調用時,開發人員通常會將GraphQL實現為,在內部REST框架之上的一個瘦代理層。如果在沒有充分考慮到安全因素的情況下實施此類轉換,那么惡意用戶就可以任意修改API請求中所指定的路徑或參數。而修改后的請求在解析到后端API時,攻擊者便可以實施跨站請求偽造( cross-site request forgery,CSRF)了。
授權缺陷
GraphQL將配置授權和身份驗證的檢查責任,留給了最終實現者。即,GraphQL API在查詢級別的解析器、以及加載附加數據的解析器中,需要包含多項授權檢查。而當授權由查詢級解析器直接處理時,任何未經檢查的API實例都會暴露受攻擊面。而且,隨著API模式復雜性的增加,此類被攻擊者利用的漏洞風險也會隨之增加。
自省查詢(Introspection Queries)可能會暴露敏感數據
開發人員為了去實現那些無法公開訪問的“隱藏”API端點,會啟用GraphQL服務器之間的API端點通信,或通過隱藏的管理功能來實現。其中,GraphQL包含了一個自省功能,可以在沒有適當授權的情況下,輕松地訪問各個端點。由于自省功能允許客戶端訪問有關GraphQL架構的信息,因此一旦有攻擊發生,自省查詢就可以被用于訪問API的相關配置、以及其他客戶端的私有信息。
速率限制難以實施
從本質上說,GraphQL API是比較復雜的。它的每一個查詢都會涉及到多項操作,并且會消耗大量的服務器資源。因此,光靠限制接收到的HTTP請求數量,并使用默認的速率限制策略是不夠的。如果兩種對象類型之間存在著某種循環關系,那么攻擊者就可以通過創建各種濫用查詢(abusive queries),從而讓查詢本身變得異常復雜。以此產生的編排,能夠對GraphQL應用發起拒絕服務式(DoS)的攻擊。
常見的GraphQL漏洞
下面,我們來進一步討論GraphQL有哪些常見的漏洞,可被惡意攻擊者在API層面利用。
GraphQL批處理攻擊
GraphQL框架能夠支持自省查詢的批處理,即:能夠在一次性調用中,向后端API發送多個請求。由于減少了請求與服務器之間的往返次數,因此這對于減少API請求的開銷非常實用。不過,攻擊者也可以使用查詢的批處理功能,通過反復從API服務器、或數據庫處加載數據,來編排各種快速且難以被檢測到的暴力攻擊。
以下典型示例展示了,在搜索數字記錄對象標識(Digital Record Object Identification,DROID)對象的不同實例時,進行GraphQL批處理查詢的代碼:
- query {
- droid(id: "2000"){
- name
- }
- second:droid(id: "2001"){
- name
- }
- third:droid(id: "2002"){
- name
- }
- }
而攻擊者可以通過制造一些網絡請求,來枚舉API服務器中的每一個droid對象。這就可能會導致API級別的DoS攻擊、暴力破解秘密數據、繞過請求的速率限制、以及對象枚舉等安全問題。
GraphQL注入攻擊
GraphQL API通常與作為數據源的數據庫管理系統相連接。API后端的Resolver在收到請求后,會根據操作集來區分查詢。在Resolver查詢數據庫時,如果其操作涉及到數據的提取,那么就會直接執行相應的獲取操作??梢?,如果來自API客戶端的數據,在未被適當清理的情況下,執行任何受信的操作,那么黑客就可以通過編排SQL/NoSQL,來實施注入攻擊。同樣,如果對輸入的清理不夠充分,攻擊者還會執行諸如LDAP注入、以及命令注入等其他形式的注入攻擊。
GraphQL CSRF攻擊
跨站請求偽造(CSRF)攻擊是指,在合法用戶不知情時,強迫Web服務器運行那些不必要的操作。當存在CSRF漏洞時,攻擊者會在當前登錄用戶的上下文,發送經過身份驗證的請求。而GraphQL類型的應用極易受到CSRF攻擊,畢竟API在接收瀏覽器的請求時,會自動接受所有的cookie(其中就包括了會話cookie)。
目前,主要有兩種類型的GraphQL CSRF攻擊:基于Post和基于Get的CSRF。由于GraphQL使用多個API層來轉換傳入的多格式請求,而且能夠影響到GraphQL應用的狀態,因此大多數CSRF攻擊通常以POST請求為目標。通常,許多開發人員會只接受設置為application/json的Content-Type標頭。例如,以下POST請求可用于發出有效的GraphQL查詢:
- POST /GraphQLHTTP/1.1
- Host: redacted
- Connection: close
- Content-Length: 100
- accept: */*
- User-Agent: ...
- content-type: application/json
- Referer: https://redacted/
- Accept-Encoding: gzip, deflate
- Accept-Language: en-US,en;q=0.9
- Cookie: ...
- {"operationName":null,"variables":{},"query":"{\n user {\n firstName\n __typename\n }\n}\n"}
服務器可以將此請求作為form-urlencoded POST請求予以接受:
- POST /GraphQLHTTP/1.1
- Host: redacted
- Connection: close
- Content-Length: 72
- accept: */*
- User-Agent: Mozilla/5.0(Macintosh; Intel Mac OS X 11_2_2)AppleWebKit/537.36(KHTML, like Gecko)Chrome/89.0.4389.82 Safari/537.36
- Content-Type: application/x-www-form-urlencoded
- Referer: https://redacted
- Accept-Encoding: gzip, deflate
- Accept-Language: en-US,en;q=0.9
- Cookie: ...
- query=%7B%0A++user+%7B%0A++++firstName%0A++++__typename%0A++%7D%0A%7D%0A
而有經驗的攻擊者則可以使用自動化掃描工具,將其轉換為CSRF的攻擊接口:
彌補GraphQL漏洞的清單
下面,我們將以清單的形式,給出一些與GraphQL安全有關的優秀實踐。
防止GraphQL注入攻擊
對于那些由LDAP、ORMs/SQL/NoSQL或XML等輔助解析器,來處理輸入信息的應用而言,我們建議開發人員做到如下方面:
- 選擇諸如參數化語句等能夠提供安全API的庫。
- 根據所選用的解析器的最佳實踐,對輸入進行轉義或編碼。
- 遵循所選模塊的文檔,以正確的方式使用該工具。畢竟,大多數語言和框架都內置了編碼/轉義功能,因此了解它們的核心功能,并選擇適合的用例是非常重要的。
預防DoS攻擊
DoS攻擊旨在使得GraphQL API變慢、甚至無法響應正常的請求。為了防御此類攻擊,我們應做到:
- 為傳入的GraphQL查詢實施深度的規則限制(depth limiting)。
- 為基礎設施和API層添加超時設定。
- 執行查詢的成本分析,以限制代價昂貴的查詢。
- 對每個API客戶端的傳入請求,實施速率限制。
GraphQL API的訪問控制
為了保護對GraphQL API的合理訪問,開發人員應該做到:
- 驗證當前用戶是否有權根據他們的請求,查看、改變、以及修改數據。
- 對端點和邊緣實施授權控制。
- 利用基于角色的訪問控制(RBAC)中間件,通過查詢和變異解析器(mutation solver),來啟用訪問控制。
- 在公共的API中禁用自省查詢。
- 禁用GraphiQL之類針對GraphQL模式的探查工具。
通用GraphQL API安全實踐
開發人員還可以用來保護GraphQL層的其他方法包括:
- 對允許的字符使用白名單。
- 為突變的輸入預先定義好對應的GraphQL模式。
- 使用單一的內部字符編碼格式,來正確地處理Unicode輸入。
- 添加分頁(pagination),以限制單個請求能夠一次性訪問到的信息量。
原文標題:Best Practices For GraphQL Security,作者:Sudip Sengupta
【51CTO譯稿,合作站點轉載請注明原文譯者和出處為51CTO.com】