web application 訪問控制

世有因果知因求果發表於2017-02-05

http://secappdev.org/handouts/2012/Jim%20Manico%20%26%20%20Eoin%20Keary/Final%20-%20Access%20Control%20Module%20v4.1.pdf

什麼是access control/authorization?

authorization is the process where a system determines if a specific user has access to a particular resource.

在上面的定義中有幾個關鍵詞: process, specific user, particular resource

authorization的目的是ensure that a user only access system functionality to which he is entitled.也就是說讓使用者具有已經賦予他的權利來訪問他可以訪問的資源

 

凡是網站有使用者就有訪問控制的需求,傳統上基於RBAC(Role based access control)可以實現粗放的訪問控制,但是RBAC也有非常明顯的問題:就是控制粒度太大,無法動態對某個資源來實現控制,要麼可以訪問,要麼不能訪問,而現實中很多情況下是:可以讀訪問部分資源,讀寫自己建立的資源,這種情況下RBAC就無能為力了。總的來說,RBAC無法解決水平訪問控制的問題(horizontal access control)

 

access control的分類

訪問控制總體來說可以分為3類: vertical, horizontal, context-dependent

vertical access control:允許不同型別的使用者訪問應用的不同功能。最簡單的情況比如將普通使用者和管理員使用者做一個垂直劃分,他們能夠訪問應用的不同部分,比如只有admin使用者能夠訪問管理後臺;在更復雜的情況下,vertical access control可能包含著定義良好的user roles並且給這些roles授權specific functions.

horizontal access control則允許使用者訪問一個相同型別大的資源池中的子集(allow users to access a certain subset of a wider range of resources of the same type)比如,一個web mail application允許你查閱你自己的email,但是不允許你檢視別人的email(儘管這些email對於系統來說就是一種相同型別的資源),一個線上銀行允許你將你的帳號的錢轉出去,但是不允許轉別人的錢,一個工作流應用允許你更新分配給你的tasks,但是卻只允許你read tasks assigned to other people(NON write access).

context-dependent access controls確保使用者的訪問許可權和當前application state有關。比如,如果一個使用者在一個長流程中的不同階段時,context-dependent access control可能拒絕你訪問未按照流程走完的訪問請求。

大多數情況下,vertical和horizontal access control是交織在一起的。比如,一個enterprise resource planning application可能允許每個應付賬店員對於他負責的organizational unit付賬,但是不允許對其他的unit付賬。而部門經理可能被允許pay invoices for any unit.類似的,店員可能被允許支付小額賬單,但是大額賬單卻只能由manager來啟動支付。而財務總監可能能夠檢視公司任何一個organizational unit的應付賬清單,但是卻不允許啟動付賬流程。

如果只要任何使用者能夠訪問未授予他許可權的functionality or resources我們都認為access control is broken.有三種主要的attacks against access controls,對應著三種access control category:

對訪問控制的惡意攻擊

1. Vertical access control attacks

    一個低許可權的使用者能夠訪問未授權給他的高許可權功能functions(a standard user accessing administration functionality)。比如,如果一個普通使用者可以執行管理功能,或者一個店員能夠啟動任何金額的應付賬,則access controls are broken

2. Horizontal access control attacks

    相同角色的使用者去訪問其他使用者的私有資料(same role, but accessing another user's private data).當一個使用者可以檢視或者修改他未被授權訪問的resource時就認為access controls are broken.比如,如果你使用web mail可以檢視其他使用者的email,或者應付賬部門員工可以處理不是他負責的部門的賬單則就認為broken

3. Business logic access control attacks

   abuse of workflow

   如果一個使用者可以利用應用的狀態機缺陷來獲取到一個關鍵resource.比如,一個使用者可能在checkout shopping cart時繞過payment step而卻實現了購物的成功。

通常一旦應用的horizontal access control缺陷可能能夠馬上導致vertical attack.比如,如果一個使用者可以找到一個辦法來設定別的使用者的密碼,那麼這個使用者可能就可以修改admin賬戶密碼從而得到對應用的絕對控制。

 

訪問控制經常存在的issues

1. 很多application僅實現了一個"all or nothing" approach:一旦authenticated那麼所有使用者都有相同的許可權

2. authorization logic通常依賴於預設環境是安全的並且會假設:使用者不會找到unlinked functionality或者說是hidden path/functionality, 使用者不會找到並且篡改那些隱藏的客戶端引數(比如:hidden form filed, cookies等)

比如:在訪問一個頁面a.com/profile時,如果他登入為administrator使用者,則在檢視層中就返回一個a.com/adminbackend的頁面連結以方便點選,而如果不登入為admin帳號則view中就不包含這個後臺連結,而對這個後臺連結遺憾的是應用並未做任何保護,那麼這種所謂的保護(僅通過根據不同使用者來決定是否顯示受限訪問連結來"保護")是假設在別人無法知道這個a.com/adminbackend url上的。一旦別人知道了這個連結直接訪問則門戶洞開。

 

3. 在應用中一旦有了多個permission level/roles這總會增加permission set間許可權衝突可能從而使得許可權系統工作紊亂

典型的許可權控制不好的實現實踐

1. 在application code中hard-coded role check

void   editProfile(User u, EditUser eu) {   if (u.isManager()) { editUser(eu)     } } 

帶來的問題: what needs to occur in order to change the access control policy of this feature?

 a. 使得證明我們已經實現了應用的授權策略非常困難

 b. 任何時候訪問控制策略policy需要變更,那麼就必須修改程式碼

 c. 脆弱而易於犯錯誤

 d. 無法實現自動化,需要在每一個application feature上來做hand-coded

 

2. 缺乏集中的訪問控制邏輯

看看下面的分散引數控制情況: 

http://example.com/buy?action=chooseDataPackage
http://example.com/buy?action=customizePackage
http://example.com/buy?action=makePayment
http://example.com/buy?action=downloadData
攻擊者可以通過concurrency就可能獲取不應有的許可權

3. 不可信資料卻驅動著訪問控制決策

 a. 永遠不要信任從客戶端來的資料做訪問控制決策

 b. 永遠不要在javascript中做訪問控制決策

 c. 永遠不要只基於以下資訊來做訪問控制決策:

    c.1: hidden fields

    c.2: cookie value

    c.3: form parameters

    c.4: url parameters

 d. 永遠不要依賴於客戶端傳送過來引數值的順序來做決策

 

4. 訪問控制遵循了"open by default”的原則,這將開放不必要的許可權

   很多administrative interfaces僅僅需要一個密碼就授權了。共享帳號而又缺乏auditing和logging會導致區分好人和壞人非常困難。admin interface往往不如user-level interface那麼安全因為總是假設administrators是值得信任的使用者

 

 

5. 缺乏解決水平訪問控制的標準方法

6. access contro邏輯必須手工地加到每一個endpoin中

攻擊訪問控制系統

1. elevation of privileges

2. 披露敏感資訊: 比如admin-level的帳號往往能夠訪問一個使用者的私密資訊

3. 資料篡改: 特權級別往往對於那些可以檢視資料的使用者和可以修改使用者的資料不加以區分

testing for broken access control

試圖作為一個匿名使用者或者一個普通使用者來訪問admin components/functions:修改html hidden form fields, 測試web accessible directory structure for names,比如admin,administrator,manager等等:即直接訪問那些受限的資源

試圖摸清administrator是如何被authenticated的。我們需要確保充足的鑑權渠道被使用,甚至可以加上普通密碼加上註冊手機得到的臨時密碼來鑑權

對於每一個user role,需要確保適當的pages或者components可以被那個role所訪問

Access control best practices:

1. 通過role based access control來對使用者assign permissions以實現vertical access control requirements;

2. 通過data-contextual access control在特定data items上下文環境中授權給特定使用者以實現horizontal access control requirements

3. 避免直接對單個使用者來做assign permissions動作

4. 對應用的所有pages都執行一致的authorization checking routings;

5. 如果可能,在最後應用apply DENY, case-by-case來 issue allow privilege

6. 實現一個集中的access control mechanism

7. code to the activity(permission), not the role

 8. 集中access control logic

9. 將access control作為一個filter或者說middleware

10. Deny by default, fail securely

11. 將相同的核心授權邏輯應用到presentation(view檢視)層和server-side access-control decisions中

12. server-side受信資料應該作為驅動access-control的資料來源頭

13. 可以在實時執行時修改一個使用者的role

14. build grouping capability for users and permissions

Code to the activity/permission

// 不再像下面的
if ((user.isManager() ||     user.isAdministrator() ||     user.isEditor() ||    user.isUser() &&     user.id() != 1132)) {     //execute action}
// 而應該像這樣:
if (AC.hasAccess(ARTICLE_EDIT)) {   //execute activity}

code it once, never needs to change again

implies policy is persisted/centralized in some way

requires more design/work up front to get right

定義一個centralized ACL Controller:定義一個集中的ACL Controller

ACLService.isAuthorized(ACTION_CONSTANT) 
ACLService.assertAuthorized(ACTION_CONSTANT)

所有的access control decision都通過這些簡單的api來實現

集中的授權邏輯驅動policy behavir and persistence

可能包含data-driven access control policy information

如何使用一個centralized access controller

1. 在檢視presntation layer:

if (isAuthorized(VIEW_LOG_PANEL)){   
<h2>Here are the logs</h2>  
<%=getLogs();%/>
} 

2. 在控制層controller中:

try (assertAuthorized(DELETE_USER)){  
 deleteUser();
}

永遠在server端驗證policy:

1. 將user id verification放在session中;

2. 從受信任的server端資料來源頭來載入entitlements

3. 對所有的requests都強制authorization check: 包括js檔案發起的request,mage, ajax, flash request都要強制authorization check, 最好通過一個通用的middleware來實現這個強制鑑權功能

 

相關文章