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

好久沒有更新文章了……這一年過得太忙。
準備一篇個人認為值得拿出來分享的文章真的需要很多時間,如果你喜歡,請評論、點贊讓我知道,我會抽更多的時間來更新一些分享給大家,謝謝!

此篇文章主要嘗試將世面上現有的一些權限系統設計做一下簡單的總結分析,個人水平有限,如有錯誤請不吝指出。

術語

這里對后面會用到的詞匯做一個說明,老司機請直接翻到常見設計模式

用戶

發起操作的主體。

對象(Subject)

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

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

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

權限 (Permission)

用來指代對某種對象的某一種操作,例如“添加文章的操作”。

權限標識

權限的代號,例如用“ARTICLE_ADD”來指代“添加文章的操作”權限。

常見設計模式

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

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

而擁有對象權限的用戶,又可以將該對象的權限分配給其他用戶,所以稱之為“自主(Discretionary)”控制。

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

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

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的微創新方案還不夠規范化從而做到普及。不過在服務化架構的浪潮下,未來這一塊必然有極高的需求,也許巨頭們已經開始布局了。

參考文檔

NTFS文件系統權限

Solaris權限模型

百度百科:訪問控制

Red Hat: Multi-Level Security (MLS)

冰云:An Introduction To Role-Based Access Control

NIST: Role-Based Access Control

MongoDB RBAC

Stackoverflow: Group vs role Any real difference?

Yii: Getting to Understand Hierarchical RBAC Scheme

Role-Based Access Control in Computer Security

(Syracuse University: Role-Based Access Control (RBAC)

Yii 2.0 Guide

WIKIPEDIA: Computer access control

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,695評論 2 370

推薦閱讀更多精彩內容