2010-06-09 76 views
8

我們使用ASP.NET進行大量AJAX「Page Method」調用。 頁面中定義的WebServices會從我們的BusinessLayer調用方法。 爲了防止黑客調用Page方法,我們希望在BusinessLayer中實現一些安全性。制定業務層安全的方法。最佳做法/最佳模式

我們正在努力解決兩個不同的問題。

第一招:

public List<Employees> GetAllEmployees() 
{ 
    // do stuff 
} 

這個方法應該通過與角色 「HR」 授權用戶調用。

第二個:

public Order GetMyOrder(int orderId) 
{ 
    // do sutff 
} 

此方法應該僅由訂單的所有者被調用。

我知道這很容易實現像每個方法的安全性:

public List<Employees> GetAllEmployees() 
{ 
    // check if the user is in Role HR 
} 

public Order GetMyOrder(int orderId) 
{ 
    // check if the order.Owner = user 
} 

什麼我要找的是實現這種安全的一些模式/最佳實踐(不用編碼if then then每次) 我希望你明白我的意思:-)

+1

我看到你已經在SO一段時間了。不過,我會建議您將標籤([.net/c#])留在標題之外。讓他們留在標籤中。此外,「嗨」和「謝謝」雖然適合討論論壇,但並不適用於SO等問答站點。謝謝。 – 2010-06-10 04:28:59

+0

@John好的。感謝提示。 – gsharp 2010-06-10 06:30:25

回答

9

User @ mdma描述了一些關於面向方面編程的內容。爲此,您需要使用外部庫(例如偉大的PostSharp),因爲.NET沒有太多的AOP功能。但是,。NET已經有了基於角色的安全的AOP機制,可以解決你的部分問題。看的標準.NET代碼下面的例子:

[PrincipalPermission(SecurityAction.Demand, Role="HR")] 
public List<Employees> GetAllEmployees() 
{ 
    // do stuff 
} 

PrincipalPermissionAttribute是位於System.Security.Permissions命名空間的一部分,並且是.NET(因爲.NET 1.0)的一部分。我已經使用它多年來已經在我的web應用程序中實現基於角色的安全性。關於這個屬性的好處在於,.NET JIT編譯器可以在後臺爲你編織所有內容,甚至可以在類級別上定義它。在這種情況下,該類型的所有成員都將繼承該屬性及其安全設置。

當然它有其侷限性。您的第二個代碼示例不能使用基於.NET角色的安全屬性實現。我認爲你不能真正圍繞這種方法進行一些自定義安全檢查,或者調用一些內部安全庫。

public Order GetMyOrder(int orderId) 
{ 
    Order o = GetOrderInternal(orderId); 
    BusinessSecurity.ValidateOrderForCurrentUser(o); 
} 

當然你也可以使用一個AOP框架,但你仍然會寫,這將再次撥打您自己的安全層的框架的具體屬性。只有當這樣一個屬性可以代替多個方法調用時,這纔會有用,例如當必須將代碼放入try,catch,finally語句時。當你做一個簡單的方法調用時,單個方法調用或單個屬性IMO之間沒有太大的區別。

當您返回對象的集合,並希望篩選出當前用戶沒有適當權限的所有對象,LINQ表達式樹可以派上用場:

public Order[] GetAllOrders() 
{ 
    IQueryable orders = GetAllOrdersInternal(); 
    orders = BusinessSecurity.ApplySecurityOnOrders(orders); 
    return orders.ToArray(); 
} 

static class BusinessSecurity 
{ 
    public static IQueryable<Order> ApplySecurityOnOrders(
     IQueryable<Order> orders) 
    { 
     var user = Membership.GetCurrentUser(); 

     if (user.IsInRole("Administrator")) 
     { 
      return orders; 
     } 

     return 
      from order in orders 
      where order.Customer.User.Name == user.Name 
      select order; 
    } 
} 

當你的O/RM通過表達式樹(例如NHibernate,LINQ to SQL和Entity Framework)支持LINQ,您可以編寫一次這樣的安全方法並將其應用到任何地方。當然,關於這一點的好處是,對數據庫的查詢總是最優的。換句話說,沒有更多的記錄將被檢索超過需要。

UPDATE(年後):

我用這個屬性在我的代碼基礎很長一段時間,但幾年後,我來到了這個屬性基於AOP有可怕的缺點的結論。例如,它阻礙了可測試性。由於安全代碼是用普通代碼編織的,因此無法運行正常的單元測試而無需模擬有效的用戶。這是脆弱的,不應該成爲單元測試的考慮因素(單元測試本身違反單一職責原則)。除此之外,它強制你用這個屬性拋棄你的代碼庫。

因此,我寧願用decorators來包裝代碼,而不是使用PrincipalPermissionAttribute來代替安全性。這使得我的應用程序更加靈活並且更容易測試。在過去的幾年中,我已經寫了幾篇關於這種技術的文章(例如this onethis one)。

0

如果您使用SOA,您可以創建一個安全服務,並且每個動作(方法)都會發送它的上下文(UserId,OrderId等)。安全服務知道有關業務安全規則。

方案可能是這樣的

UI -> Security -> BLL -> DAL 
+0

任何樣品/文獻? – gsharp 2010-06-10 06:33:34

+1

我同意將安全性置於應用程序級別,而不是像其他答案那樣在「框架」級別。如果角色是動態的呢? – 2010-06-16 16:13:45

2

一個「最佳實踐」是實現安全性的一個方面。這使得安全規則與主要業務邏輯分開,避免了硬編碼,並使得在不同環境中更改安全規則變得容易。

以下文章列出了7種實現方面並保持代碼獨立的方法。一種簡單且不改變業務邏輯接口的方法是使用代理。這暴露了與當前相同的接口,但允許替代實現,它可以修飾現有的實現。可以使用硬編碼或自定義屬性將安全需求注入此接口。代理攔截方法調用您的業務層並調用適當的安全檢查。在這裏詳細描述通過代理實現攔截 - Decouple Components by Injecting Custom Services into your Object's Invocation Chain。其他AOP方法在Understanding AOP in .NET中給出。

下面是一個forum post討論安全作爲一個方面,實施使用建議和安全屬性。最終的結果是

public static class Roles 
{ 
    public const string ROLE_ADMIN = "Admin"; 
    public const string ROLE_CONTENT_MANAGER = "Content Manager"; 
} 

// business method  
[Security(Roles.ROLE_HR)] 
public List<Employee> GetAllEmployees(); 

您可以直接把屬性對您的業務方法,緊耦合,或者創建具有這些屬性的服務代理,所以安全細節保持獨立。

+0

在我看來,解決方案與框架太緊密(通過裝飾方法)。我將實現作爲系統一部分的安全功能,因爲它不像業務邏輯之外那樣。我喜歡代理建議雖然..我2美分。 – 2010-06-16 16:18:34

+0

@Mike - 屬性是你自己的,所以我不明白這是如何綁定到任何框架。它們是實現細節 - 聲明式安全而不是編寫代碼。你仍然可以自由地編寫代碼,但是將代碼放在業務對象本身上是OP說他想避免的。當這些屬性放在業務對象上時,它們仍然與代碼「分離」 - 即易於識別。如果您將安全檢查作爲代碼並將其放入業務邏輯中,情況並非如此。 – mdma 2010-06-16 16:41:58

+0

嗨,我看到它就像硬編碼。這就是爲什麼我說「框架」很抱歉。如果角色是動態的呢?我會創建像「User」對象一樣的安全對象,因爲它們與其他任何東西一樣是系統的一部分。 – 2010-06-16 19:27:30