轉:權限系統設計模型分析(DAC,MAC,RBAC,ABAC)

 

 
 

術語

這裏對後面會用到的詞彙作一個說明,老司機請直接翻到常見設計模式。php

用戶

發起操做的主體。html

對象(Subject)

指操做所針對的客體對象,好比訂單數據或圖片文件。mongodb

權限控制表 (ACL: Access Control List)

用來描述權限規則或用戶和權限之間關係的數據表。數據庫

權限 (Permission)

用來指代對某種對象的某一種操做,例如「添加文章的操做」。apache

權限標識

權限的代號,例如用「ARTICLE_ADD」來指代「添加文章的操做」權限。centos

常見設計模式

自主訪問控制(DAC: Discretionary Access Control)

系統會識別用戶,而後根據被操做對象(Subject)的權限控制列表(ACL: Access Control List)或者權限控制矩陣(ACL: Access Control Matrix)的信息來決定用戶的是否能對其進行哪些操做,例如讀取或修改。設計模式

而擁有對象權限的用戶,又能夠將該對象的權限分配給其餘用戶,因此稱之爲「自主(Discretionary)」控制。安全

這種設計最多見的應用就是文件系統的權限設計,如微軟的NTFS。架構

DAC最大缺陷就是對權限控制比較分散,不便於管理,好比沒法簡單地將一組文件設置統一的權限開放給指定的一羣用戶。app

 
Windows的文件權限

強制訪問控制(MAC: Mandatory Access Control)

MAC是爲了彌補DAC權限控制過於分散的問題而誕生的。在MAC的設計中,每個對象都都有一些權限標識,每一個用戶一樣也會有一些權限標識,而用戶可否對該對象進行操做取決於雙方的權限標識的關係,這個限制判斷一般是由系統硬性限制的。好比在影視做品中咱們常常能看到特工在查詢機密文件時,屏幕提示須要「沒法訪問,須要一級安全許可」,這個例子中,文件上就有「一級安全許可」的權限標識,而用戶並不具備。

MAC很是適合機密機構或者其餘等級觀念強烈的行業,但對於相似商業服務系統,則由於不夠靈活而不能適用。

 
RedHat MLS

Red Hat: MLS

基於角色的訪問控制(RBAC: Role-Based Access Control)

由於DAC和MAC的諸多限制,因而誕生了RBAC,而且成爲了迄今爲止最爲普及的權限設計模型。

RBAC在用戶和權限之間引入了「角色(Role)」的概念(暫時忽略Session這個概念):

 
RBAC核心設計

圖片來自Apache Directory

如圖所示,每一個用戶關聯一個或多個角色,每一個角色關聯一個或多個權限,從而能夠實現了很是靈活的權限管理。角色能夠根據實際業務需求靈活建立,這樣就省去了每新增一個用戶就要關聯一遍全部權限的麻煩。簡單來講RBAC就是:用戶關聯角色,角色關聯權限。另外,RBAC是能夠模擬出DAC和MAC的效果的。

例如數據庫軟件MongoDB即是採用RBAC模型,對數據庫的操做都劃分紅了權限(MongoDB權限文檔):

權限標識 說明
find 具備此權限的用戶能夠運行全部和查詢有關的命令,如:aggregate、checkShardingIndex、count等。
insert 具備此權限的用戶能夠運行全部和新建數據有關的命令:insert和create等。
collStats 具備此權限的用戶能夠對指定database或collection執行collStats命令。
viewRole 具備此權限的用戶能夠查看指定database的角色信息。
 

基於這些權限,MongoDB提供了一些預約義的角色(MongoDB預約義角色文檔,用戶也能夠本身定義角色):

角色 find insert collStats viewRole
read    
readWrite  
dbAdmin    
userAdmin      

最後授予用戶不一樣的角色,就能夠實現不一樣粒度的權限分配了。

目前市面上絕大部分系統在設計權限系統時都採用RBAC模型。然而也有的系統錯誤地實現了RBAC,他們採用的是判斷用戶是否具備某個角色而不是判斷權限,例如如下代碼:

<?php if ($user->hasRole('hr')) { // 執行某種只有「HR」角色才能作的功能,例如給員工漲薪… // ... } 

若是後期公司規定部門經理也能夠給員工漲薪,這時就不得不修改代碼了。

以上基本就是RBAC的核心設計(RBAC Core)。而基於核心概念之上,RBAC規範還提供了擴展模式。

角色繼承(Hierarchical Role)

 
RBAC 1

帶有角色繼承的RBAC。圖片來自Apache Directory

顧名思義,角色繼承就是指角色能夠繼承於其餘角色,在擁有其餘角色權限的同時,本身還能夠關聯額外的權限。這種設計能夠給角色分組和分層,必定程度簡化了權限管理工做。

職責分離(Separation of Duty)

爲了不用戶擁有過多權限而產生利益衝突,例如一個籃球運動員同時擁有裁判的權限(看一眼就給你判犯規狠不狠?),另外一種職責分離擴展版的RBAC被提出。

職責分離有兩種模式:

  • 靜態職責分離(Static Separation of Duty):用戶沒法同時被賦予有衝突的角色。
  • 動態職責分離(Dynamic Separation of Duty):用戶在一次會話(Session)中不能同時激活自身所擁有的、互相有衝突的角色,只能選擇其一。
 
RBAC 2

靜態職責分離。圖片來自Apache Directory

 
RBAC 3

動態職責分離。圖片來自Apache Directory

講了這麼多RBAC,都還只是在用戶和權限之間進行設計,並無涉及到用戶和對象之間的權限判斷,而在實際業務系統中限制用戶可以使用的對象是很常見的需求。例如華中區域的銷售沒有權限查詢華南區域的客戶數據,雖然他們都具備銷售的角色,而銷售的角色擁有查詢客戶信息的權限。

那麼咱們應該怎麼辦呢?

用戶和對象的權限控制

在RBAC標準中並無涉及到這個內容(RBAC基本只能作到對一類對象的控制),可是這裏講幾種基於RBAC的實現方式。

首先咱們看看PHP框架Yii 1.X的解決方案(2.X中代碼更爲優雅,但1.X的示例代碼更容易看明白):

<?php $auth=Yii::app()->authManager; $auth->createOperation('createPost','create a post'); $auth->createOperation('readPost','read a post'); $auth->createOperation('updatePost','update a post'); $auth->createOperation('deletePost','delete a post'); // 主要看這裏。 // 這裏建立了一個名爲`updateOwnPost`的權限,而且寫了一段代碼用來檢驗用戶是否爲該帖子的做者 $bizRule='return Yii::app()->user->id==$params["post"]->authID;'; $task=$auth->createTask('updateOwnPost','update a post by author himself',$bizRule); $task->addChild('updatePost'); $role=$auth->createRole('reader'); $role->addChild('readPost'); $role=$auth->createRole('author'); $role->addChild('reader'); $role->addChild('createPost'); $role->addChild('updateOwnPost'); $role=$auth->createRole('editor'); $role->addChild('reader'); $role->addChild('updatePost'); $role=$auth->createRole('admin'); $role->addChild('editor'); $role->addChild('author'); $role->addChild('deletePost'); 

實現效果:

 
Yii 1.X權限圖

圖片來自Yii官方WiKi

在這個Yii的官方例子中,updateOwnPost在判斷用戶是否具備updatePost權限的基礎上更進一步判斷了用戶是否有權限操做這個特定的對象,而且這個判斷邏輯是經過代碼設置的,很是靈活。

不過大部分時候咱們並不須要這樣的靈活程度,會帶來額外的開發和維護成本,而另外一種基於模式匹配規則的對象權限控制可能更適合。例如判斷用戶是否對Id爲123的文章具備編輯的權限,代碼多是這樣的:

<?php // 假設articleId是動態獲取的 $articleId = 123; if ($user->can("article:edit:{$articleId}")) { // ... } 

而給用戶受權則有多種方式能夠選擇:

<?php // 容許用戶編輯Id爲123的文章 $user->grant('article:edit:123'); // 使用通配符,容許用戶編輯全部文章 $user->grant('article:edit:*'); 

雖然不及Yii方案的靈活,但某些場景下這樣就夠用了。

若是你們還有更好的方案,歡迎在評論中提出。

基於屬性的權限驗證(ABAC: Attribute-Based Access Control)

ABAC被一些人稱爲是權限系統設計的將來。

不一樣於常見的將用戶經過某種方式關聯到權限的方式,ABAC則是經過動態計算一個或一組屬性來是否知足某種條件來進行受權判斷(能夠編寫簡單的邏輯)。屬性一般來講分爲四類:用戶屬性(如用戶年齡),環境屬性(如當前時間),操做屬性(如讀取)和對象屬性(如一篇文章,又稱資源屬性),因此理論上可以實現很是靈活的權限控制,幾乎能知足全部類型的需求。

例如規則:「容許全部班主任在上課時間自由進出校門」這條規則,其中,「班主任」是用戶的角色屬性,「上課時間」是環境屬性,「進出」是操做屬性,而「校門」就是對象屬性了。爲了實現便捷的規則設置和規則判斷執行,ABAC一般有配置文件(XML、YAML等)或DSL配合規則解析引擎使用。XACML(eXtensible Access Control Markup Language)是ABAC的一個實現,可是該設計過於複雜,我尚未徹底理解,故不作介紹。

總結一下,ABAC有以下特色:

  1. 集中化管理
  2. 能夠按需實現不一樣顆粒度的權限控制
  3. 不須要預約義判斷邏輯,減輕了權限系統的維護成本,特別是在需求常常變化的系統中
  4. 定義權限時,不能直觀看出用戶和對象間的關係
  5. 規則若是稍微複雜一點,或者設計混亂,會給管理者維護和追查帶來麻煩
  6. 權限判斷須要實時執行,規則過多會致使性能問題

既然ABAC這麼好,那最流行的爲何仍是RBAC呢?

我認爲主要仍是由於大部分系統對權限控制並無過多的需求,並且ABAC的管理相對來講太複雜了。Kubernetes便由於ABAC太難用,在1.8版本里引入了RBAC的方案

ABAC有時也被稱爲PBAC(Policy-Based Access Control)或CBAC(Claims-Based Access Control)。

結語

權限系統設計可謂博大精深,這篇文章只是介紹了一點皮毛。

隨着人類在信息化道路上越走越遠,權限系統的設計也在不斷創新,但目前好像處在了平臺期。

可能由於在RBAC到ABAC之間有着巨大的鴻溝,沒法輕易跨越,也多是一些基於RBAC的微創新方案還不夠規範化從而作到普及。不過在服務化架構的浪潮下,將來這一塊必然有極高的需求,也許巨頭們已經開始佈局了

相關文章
相關標籤/搜索