管理好API安全性
API的安全性涉及到各種端到端的數據保護,它們依次包括:來自客戶端的請求經由網絡到達服務器/后端,由服務器/后端發送相應的響應,響應橫跨網絡,最后到達客戶端,這一系列的過程。因此,API的安全性可以大致分為如下四種不同的類別,我們將逐一進行詳細討論:
(1)傳輸中的數據安全
· 保護客戶端與API網關之間的動態數據
· 保護API網關與后端服務之間的動態數據
(2)訪問控制與抵御拒絕服務(DoS)攻擊
(3)身份驗證與授權:使用OAuth2.0或OpenID Connect,來可靠地識別最終用戶的信息
(4)數據保密與屏蔽個人身份信息(Personally Identifiable Information,PII)
1. 傳輸中的數據安全
對于所有公共且不受保護的API來說,我們必須用到TLS。如今隨著硬件的進步,TLS的實施開銷幾乎可以忽略不計了,而且隨著延遲在逐漸減小,越來越多的最終用戶會處于安全考慮而選用TLS。總的說來,TLS具有如下主要特點:
· TLS應當在北向(northbound)和南向(southbound)端點同時實施。
· 應確保使用TLS的最新版本,并對客戶端、API網關和目標后端予以支持。
· 證書密鑰、以及信任憑證的存儲都應該受到高度保護和加密。
· 只有經過授權的用戶才能訪問證書密鑰、以及信任憑證。
2. 訪問控制與抵御拒絕服務(DoS)攻擊
(1) 網絡級別的防御:如果API網關被托管在云端,則需要使用由云服務商所提供的 DDoS防御機制,例如:由Apigee(Google)所運營的Apigee Edge托管云平臺、 GCP(Google云平臺)和AWS(Amazon Web),它們都提供了網絡級別的DDoS防御。
(2) 內容交付網絡:像Akamai、Neustar和Rackspace之類的CDN,都可以用于緩解那些對于API的DDoS攻擊。
(3) “僵尸”檢測:如今各大API管理平臺都已經針對僵尸/機器人類型的攻擊,推出了檢測API流量,識別各種惡意/非必要請求,并生成警報/阻止惡意請求到達的API網關服務。例如:Apigee(Google)提供了一種稱為“Apigee Sense”的檢測服務。它是一種智能數據驅動的API安全產品,它可以通過自動識別各種可疑的API客戶端行為,以提供額外的保護層。同時,管理員也可以在此基礎上通過糾正性措施,來保證用戶的體驗度,以及后端系統的安全性。
(4) 策略執行:我們應該在位于API客戶端和客戶后端之間的API代理上,通過強制實施各種策略,以嚴格管控合法用戶對于API的訪問。如下策略能夠在一定程度上保護API免受惡意黑客的攻擊:
· API速率限制:通過限速,我們可以減少大量導致拒絕服務的API請求,并抑制暴力攻擊和服務濫用。特別是在API代理服務器上,我們可以采用如下限速的機制:
· 基于應用程序或個別API予以限速,以保證每個API或應用程序只能按照固定的請求數配額,去訪問對應的服務。
· 基于GET或POST請求予以限速,當然具體的請求數設定,可以根據不同時段的GET或POST量而有所不同。
(5) 正則表達式保護:應當根據預定義的正則表達式(如DELETE、UPDATE和EXECUTE)來評估入棧請求的URI路徑、查詢參數、包頭、表格參數、變量、XML有效負載、以及JSON負載。任何匹配上了預定義表達式的請求都將被視為威脅,并被立即拒絕掉。請參閱OWASP top 10(https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project#OWASP_Top_10_for_2013),以了解具體有關要如何驗證正則表達式的信息。
(6) JSON輸入驗證:對于PUT/POST/DELETE之類請求的負載,我們應執行JSON驗證,以通過指定對于各種JSON結構的限制(如最大深度、對象的最大數量、最長字符串長度的名稱、以及數組中所允許的最大元素數等),來最小化可能受到的攻擊面。
(7) XML輸入驗證:應當對PUT/POSTE/DELETE之類請求的負載執行XML驗證。具體可使用如下方法來根據配置的限制,以檢測XML負載的各類攻擊、以及監控針對XML的威脅:
· 根據XML的架構(.xsd)來驗證消息
· 根據特定黑名單里的關鍵字與模式,來評估消息內容
· 在分析消息之前,檢測出已損壞或格式錯誤的消息
(8) 驗證請求
· 驗證輸入HTTP動詞:適當地對那些允許類動詞做出限制,而對于其他所有動詞,則返回相應的響應代碼(如:“403禁止錯誤”)。
· 驗證包頭:應當根據API所支持的功能,顯式地驗證“內容類型”、“接受”和“內容長度”等包頭。此外,還應該執行針對強制性包頭(如:授權、以及特定類型的API包頭)的驗證。
· 驗證入棧內容類型:對于PUT/POST/DELETE之類入棧請求的內容類型(例如:應用/XML或應用/JSON)、以及內容類型的包頭值進行驗證。對于缺少內容類型的包頭、或異常內容類型的包頭,應當直接拒絕,并返回“406不可接受”的響應內容。
· 驗證響應類型:不要簡單地將“接受”包頭復制到響應內容類型的包頭中。如果“接受”包頭中并沒有明確地包含允許的類型,應當直接拒絕該請求,并返回“406不可接受”的響應內容。
· 處置不支持的資源:適當通過限制資源,只開放可供調用的資源;而對于其他所有未實現的資源,則應返回“未知資源”之類相應的響應代碼。
(9) 訪問控制:通過配置策略,只允許來自特定IP地址、域名或區域的請求。而那些未通過此類條件的請求,應當被網關直接拒絕掉。
3. 身份驗證和授權
通常情況下,身份驗證和授權是同步發生的。
· 身份驗證常被用于識別最終用戶。
· 授權則被用于授予已識別用戶訪問某些資源的權限。
在API領域中,OAuth和OpenID Connect是最為常用的機制。它們通過利用現有的IAM架構,并以交換訪問令牌的方式,來驗證用戶的身份,進而保護API的各個端點。通過OAuth和OpenID Connect,我們不需要每次都構建單獨的系統,以存儲用戶名和密碼的方式,來匹配用戶可以訪問的API資源。
OAuth
OAuth通常采用不透明(OPAQUE)令牌,來實現委托訪問(Delegated Access)的目的。OAuth2.0授權框架使得第三方應用能夠獲得對于HTTP服務的有限訪問權限。通常,用戶不應當為了訪問某些存儲在第三方的受保護數據,而在公網上傳輸自己的密碼。而OAuth恰好能夠為用戶訪問自己的數據,提供了信任憑據的安全保護。
OAuth不是一種身份驗證協議,而是授權協議。由于身份驗證通常發生在頒發訪問令牌之前,因此我們很容易理解為在接受訪問令牌時,也進行了身份驗證。然而,僅憑擁有訪問令牌,并不能證明用戶的身份。在OAuth中,令牌被設計為對客戶端來說是不透明的,客戶端僅能從令牌中獲取權限信息,而不會涉及到用戶名與密碼。
不透明令牌:在許多的具體實現中,OAuth2.0會返回OPAQUE字符串,用以換取被稱為訪問令牌的用戶憑據,而這些令牌將被進一步用于訪問各種API的資源。不透明令牌并非用來存儲用戶身份標識與信息,而是指向了某個數據庫里的具體數據項。例如:我們可以用Redis來存儲各種鍵-值(key-value)。而Cassandra之類的NoSQL數據庫則非常適合利用內存中的哈希表,根據I/O來查找有效負載。由于用戶角色是直接從數據庫中被讀出的,因此我們可以通過更改后端的角色,來傳遞并展現給用戶。
OpenID Connect
OpenID Connect采用ID令牌和訪問令牌,來實現用戶識別與委托訪問。OpenID Connect是進行用戶身份驗證的標準。由于直接構建在OAuth2.0之上,因此在大多數情況下,OpenID Connect是與OAuth架構一起被部署的。在交付形式上,它還為客戶端提供OpenID Connect令牌。該身份令牌是一個已簽名的JSON Web令牌(JWT),它與常規的OAuth訪問令牌一起被提交給客戶端應用程序。
· JSON Web令牌:JWT令牌實際上是一個完整的JSON對象。它經歷了base64編碼之后,使用對稱共享密鑰、或公/私鑰的方式進行簽名。JWT可以包含諸如:主題、user_id、令牌頒發時間、以及過期時間等信息。通過密鑰簽名,它可以確保只對擁有授權訪問密鑰的系統才能生成令牌。不過值得注意的是,系統在對JWT進行簽名時,JWT通常不會被加密(當然,您也可以選擇對其進行加密)。那么,這就意味著任何擁有令牌訪問權限的人都可以讀取令牌里的數據。因此,業界的最佳實踐是:只把用戶標識(如user_id)放在令牌中,而不是個人身份信息(如電子郵件或社會保障號碼)。此外,它們應當通過TLS之類的加密通道來進行傳遞。
· JWT限制:鑒于日常對于用戶的禁用、以及添加或刪除角色往往需要一段時間才能同步生效,而且由于令牌存儲在客戶端,即使我們在數據庫中對其所頒發的JWT用戶進行了禁用標記的話,也無法直接讓該令牌及時無效。雖然JWT采取了預定義到期的機制,但是用戶仍然需要等待到期。顯然這會影響到用戶的服務架構,特別是那些電商類的應用。
當然,業界也提供了一些變通的方法。例如:您可以使用帶有令牌或user_id的黑名單,但是這需要向數據庫引入新的認證機制。因此,一種推薦的方法是:通過黑名單以確保每個令牌都帶有一個JTI聲明(或帶有一個存儲在數據庫中的JWT Id)。因此,只要您希望注銷的令牌數量遠小于應用程序中的用戶數量,那么操作起來就非常靈活。
可見,對于那些擁有管理員、項目所有者、服務客戶經理等多種角色的企業應用來說,切換用戶的不同角色并不會對JWT立即生效。例如:管理員修改了某個授權用戶的角色,那么只要他不去刷新JWT,也就無法獲悉該變更。
下面是OpenID Connect的三種實現用例:
· 出棧方向的Web單一登錄(SSO):向企業用戶提供對于SaaS應用、以及合作伙伴應用的訪問管控,但并不公開本企業的用戶名與密碼。
· 入棧方向的Web單一登錄:允許社交賬號/第三方登錄,但無需存儲外部用戶與密碼。
· 實現各種本地應用的原生單一登錄。
OAuth和OpenID Connect都支持OAuth2規范所指定的四種授權類型,下圖描述了其中一種授權流程圖。API開發人員可以根據手頭項目所需的約束與實現方案,來選用不同的授權類型。
4. 數據保密與屏蔽個人身份信息
眾所周知,由于密碼、安全令牌和API密鑰包含了不同程度的內部信息,它們不應該出現在URL中,或者被Web服務器的日志所捕獲。此外,諸如UserID、密碼、帳號、信用卡號碼等個人身份信息,也應該處于“被打碼”的狀態,哪怕是在交易和審計日志中。
公共API的安全實踐
由于獨立于任何用戶,因此公共API的設計初衷就是為了公開各種非敏感、以及只讀的數據(例如天氣類API),當然也就不必添加任何身份驗證與授權環節。不過,我建議您通過如下的方面,來打造能夠應對各種威脅與濫用的API:
· 在IP地址級別上應用速率限制的相關策略。
· 使用API密鑰驗證的方式。通過存儲在網關上的方式,保證API的密鑰不會被公布給任何客戶端。因此,當拒絕服務攻擊使用無效密鑰訪問API、或是在其他策略已無法阻斷黑客攻擊時,API密鑰驗證方式能夠有效地發揮作用。
· 采用配額策略(單個或多種配額機制),來實現API的使用限制。
· 如果API被用于特定地理區域的服務器進行通信,那么就應當在地理級別上(縣/區等)采取IP地址的篩選。
· 開發人員應盡量采用一次性注冊的方式,并使用自己的API密鑰去調用API。
結論
在企業內部、以及企業之間需要集成不同的應用時,開發人員能夠通過API來快速且方便地予以實現。不過,如果沒有恰當地保護好API,那么就會讓整個企業面臨各種風險與威脅。因此,我們需要在開發和實施之前,就對API的安全性進行良好的構建和設計,從而提高企業的整體安全態勢。