概述
在安全管理系統裏面,授權(Authorization)的概念常常是和認證(Authentication)、賬號(Account)和審計(Audit)一起出現的,並稱之爲 4A。就像上一文章提到的,對於安全模塊的實現,最好都遵循行業標準和最佳實踐,授權也不例外。
作爲安全系統的一部分,授權的職責如下:
- 確保授權過程的可控:常見的參考標準有 OAuth2、SAML2、CAS 等協議
- 確保授權結果的可控:常見的參考標準有 RBAC、ABAC 等授權模型
對於大多數應用來說,主流的做法是基於 OAuth2 + RBAC 的組合搭配實現授權。下面就從這兩個方向展開聊聊。
RBAC
RBAC(角色基礎訪問控制)是一種常見的權限管理方式。在這種模型中,系統根據用戶的角色來分配權限,而不是直接分配給單個用戶。這樣可以簡化權限管理和配置的複雜性。避免頻繁的對用戶進行權限操作。如下:
如果還有更復雜的訪問控制需求,則可以在 RBAC0 的基礎上可以擴展 RBAC1 (層次化 RBAC,角色之間有繼承關係)和 RBAC2(受約束的 RBAC,角色之間有互斥關係)來提高系統的安全性和管理的便利性。還有 RBAC 3 等等。
對於大多數應用來說,通常都無需自己去實現這些理論的模型,應用遇到的安全問題大多都是相同的,具有普遍性,所以可以抽象到框架層面來解決,例如著名的 Spring Security 框架就提供 RBAC 模型的授權實現。
不過,需要特別說明的是,與具備通用性的訪問控制權限相比,對於數據權限的控制則顯的困難的多,用戶能訪問的數據權限通常與業務高度關聯,具體到不同部門,不同角色,甚至指定人員可以訪問的數據權限都不盡相同。完全不具備通用性,所以無法通過框架層面解決,就連 Spring Security 框架也未能提供數據權限的相關控制。只能有業務系統結合實際情況各自在業務層實現,這也是目前無法解決的問題。
OAuth 2
OAuth2 是一種業界標準的授權協議,允許用戶授權第三方應用程序訪問他們在其他服務提供者上的資源,而無需分享用戶名和密碼,它定義了四種授權交互模式,適用於各種應用場景:
- 授權碼模式
- 隱式授權
- 用戶模式
- 應用模式
OAuth2 通過發放訪問令牌(Access Token)和刷新令牌來實現對受保護資源的訪問控制。通過創新的使用訪問令牌 Token 替代了用戶密碼,避免用戶憑證的泄露。
授權碼
授權碼模式可以說是最安全的授權模式,綜合考慮了各種風險和防範措置,但相對也是最複雜的授權協議,適合有服務端可以存儲密鑰(ClientSecret)的場景,授權流程如下:
看完授權碼的過程,你可能會覺得好奇:爲什麼授權服務器要返回授權碼,而不直接返回令牌呢 ?
返回授權碼而不是直接返回令牌的設計主要是爲了提高安全性,原因如下:
- 即使授權碼被截獲,攻擊者因爲沒有客戶端密鑰無法獲取訪問令牌,客戶端密鑰只在服務器端保存,不會通過前端暴露。
- 在重定向回客戶端應用的過程中,授權碼會通過瀏覽器傳輸。如果直接傳輸訪問令牌,一旦泄露,就會帶來更高的安全風險。授權碼則可以進行嚴格的限制(如一次性使用,很短的有效期),所以即使泄露也難以被利用。
- 在客戶端使用授權碼請求訪問令牌時,授權服務器可以驗證請求中包含的客戶端密鑰和重定向 URI 等信息,確保令牌的請求合法
另外令牌頒發的策略上,授權碼模式下也使用長刷新令牌 + 短訪問令牌的雙令牌策略,來最大化減少 JWT 令牌無狀態難回收的問題。因此,在服務端可以存儲令牌的前提下,授權碼模式可以說是大多數場景下的首選。
隱式授權
隱式授權模式對於實在沒有服務端存儲 ClientSecret 的純前端應用提供接入支持。接入流程也比較簡單,如下:
該模式下用戶認證通過後授權服務器就直接向客戶端返回令牌,無需應用提供 ClientSecret 和通過授權碼獲取令牌的步驟。但是代價是安全等級降低,令牌有可能在重定向的時候暴露給攻擊者。
爲了挽救安全等級的問題,OAuth 2 也儘可能做了最大的努力,例如:
- 限制第三方應用的回調 URI 地址必須與註冊時提供的域名一致
- 在隱式模式中明確禁止發放刷新令牌
- 令牌必須是 “通過 Fragment 帶回” 的(意味着只能通過 Script 腳本來讀取,具體參考 RFC 3986)
可以看到隱式授權已經盡最大努力地避免了令牌泄漏出去的可能性。也並非主流的 OAuth 2 接入方式,若非迫不得已,大多數場合不推薦使用。
密碼模式
主要是用於一些非瀏覽器的接入場景,如果要採用密碼模式,那“第三方”屬性就必須弱化,把“第三方”視作是系統中與授權服務器相對獨立的子模塊,在物理上獨立於授權服務器部署,但是在邏輯上與授權服務器仍同屬一個系統,這樣將認證和授權一併完成的密碼模式纔會有合理的應用場景:
密碼模式非常簡單,就是拿着用戶名和密碼向授權服務器換令牌而已。在密碼模式下 OAuth2 不負責保障安全,只能由用戶和第三方應用來自行提供安全保障。
客戶端模式
以應用爲主體的授權模式,不涉及到用戶的登錄行爲,是客戶端模式是指第三方應用以自己的名義,向授權服務器申請許可憑證。用來訪問受保護資源,如下:
客戶端模式通常是用於微服務之間的訪問,例如一些定時任務,應用之間訪問授權的操作。在微服務架構並不提倡同一個系統的各服務間有默認的信任關係,所以服務之間調用也需要先進行認證授權,然後才能通信。例如應用層常見的微服務框架 Spring Cloud
就是採用該方案保證服務間的合法調用。