使业务层的方法安全。最佳实践/最佳模式 [英] Make a Method of the Business Layer secure. best practice / best pattern

查看:118
本文介绍了使业务层的方法安全。最佳实践/最佳模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用ASP.NET与很多AJAXPage Method调用。
页面中定义的WebServices会调用BusinessLayer中的方法。
为了防止黑客调用页面方法,我们要在BusinessLayer中实现一些安全性。



我们正在努力解决两个不同的问题。

第一个:

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

该方法应由授权用户使用角色HR调用。



第二个:

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

此方法只能由订单的所有者调用。



我知道实现每种方法的安全性很简单如:

  public List< Employees> GetAllEmployees()
{
//检查用户是否在角色HR
}

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

我正在寻找的是一些模式/最佳实践以通用的方式实现这种安全性(不需要每次编码if if else)
我希望你得到我的意思: - )

解决方案

用户@mdma描述了面向方面的编程。为此,您将需要使用外部库(如PostSharp),因为.NET没有太多的AOP功能。但是,.NET已经具有基于角色的安全性的AOP机制,可以解决您的部分问题。看看下面的标准.NET代码示例:

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

PrincipalPermissionAttribute 是系统的一部分。 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;
}

从订单中的订单
返回
其中order.Customer.User.Name == user.Name
选择订单;
}
}

当您的O / RM支持LINQ通过表达式树如NHibernate,LINQ to SQL和Entity Framework),您可以编写这样的安全方法一次,并将其应用到任何地方。当然,这样做的好处是,对数据库的查询将始终是最佳的。换句话说,不会再需要更多的记录。



更新(多年以后):



我在代码库中使用这个属性很长时间,但几年前,我得出的结论是,基于属性的AOP有可怕的缺点。例如,它阻碍了可测试性。由于安全代码以正常代码编织,因此无需假冒有效用户就无法运行正常的单元测试。这是脆弱的,不应该是单元测试的关注(单元测试本身违反单一责任原则)。此外,它强制您使用该属性丢弃您的代码库。



所以,而不是使用 PrincipalPermissionAttribute 我宁愿通过使用装饰器封装代码来应用跨安全问题。这使我的应用程序更加灵活,更容易测试。最近几年我写了几篇关于这种技术的文章(例如这一个这一个)。


We are using ASP.NET with a lot of AJAX "Page Method" calls. The WebServices defined in the Page invokes methods from our BusinessLayer. To prevent hackers to call the Page Methods, we want to implement some security in the BusinessLayer.

We are struggling with two different issues.

First one:

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

This Method should be called by Authorized Users with the Role "HR".

Second one:

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

This Method should only be called by the owner of the Order.

I know it's easy to implement the security for each method like:

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

or

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

What I'm looking for is some pattern/best practice to implement this kind of security in a generic way (without coding the the if then else every time) I hope you get what i mean :-)

解决方案

User @mdma describes a bit about Aspect Oriented Programming. For this you will need to use an external library (such as the great PostSharp), because .NET doesn’t have much AOP functionality. However, .NET already has a AOP mechanism for role based security, that can solve part of your problem. Look at the following example of standard .NET code:

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

The PrincipalPermissionAttribute is part of the System.Security.Permissions namespace and is part of .NET (since .NET 1.0). I’ve been using it for years already to implement role based security in my web applications. Nice thing about this attribute is that the .NET JIT compiler does all the weaving for you on the background and you can even define it on a class level. In that case all members of that type will inherit that attribute and its security settings.

Of course it has its limitations. Your second code sample can't be implemented using the .NET role based security attribute. I think you can’t really come around some custom security checks in this method, or calling some internal security library.

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

Of course you can use an AOP framework, but you would still have to write an framework specific attribute that will again call your own security layer. This would only get useful when such an attribute would replace multiple method calls, for instance when having to put code inside try,catch,finally statements. When you would be doing a simple method call, there wouldn’t be much difference between a single method call or a single attribute IMO.

When you are returning a collection of objects and want to filter out all objects for which the current user doesn't have the proper rights, LINQ expression trees can come in handy:

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; 
    }
}

When your O/RM supports LINQ through expression trees (such as NHibernate, LINQ to SQL and Entity Framework) you can write such a security method once and apply it everywhere. Of course the nice thing about this is, that the query to your database will always be optimal. In other words, no more records will be retrieved than needed.

UPDATE (years later):

I used this attribute for a long time in my code base, but several years back, I came to the conclusion that attribute based AOP has terrible downsides. For instance, it hinders testability. Since security code is weaved with normal code, you can't run normal unit tests without having to impersonate a valid user. This is brittle and should not be a concern of the unit test (the unit test itself violates the Single Responsibility Principle). Besides that, it forces you to litter your code base with that attribute.

So instead of using the PrincipalPermissionAttribute, I rather apply cross-cutting concerns like security by wrapping code with decorators. This makes my application much more flexible and much easier to test. I've written several articles about this technique the last couple of years (for instance this one and this one).

这篇关于使业务层的方法安全。最佳实践/最佳模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆