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