使业务层的方法安全。最佳做法/最佳模式做法、模式、业务、方法

2023-09-04 01:47:30 作者:游泳的馄饨

我们正在使用ASP.NET有很多AJAX页法的电话。 在页面中定义的Web服务调用从我们BusinessLayer方法。 为prevent黑客调用页面方法,我们要实现在BusinessLayer一些安全性。

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.

第一个:

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

此方法应该由授权用户与角色HR。

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

第二个:

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
}

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 :-)

推荐答案

用户@mdma介绍了一些关于面向方面的编程。为此,您需要使用一个外部库(如大PostSharp),因为.NET没有什么太大的AOP功能。然而,.NET已经拥有了AOP机制,基于角色的安全性,可以解决你的问题的一部分。看看标准的.NET code下面的例子:

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
}

的 PrincipalPermissionAttribute 是位于System.Security.Permissions命名空间的一部分,.NET(因为.NET 1.0)的一部分。我已经使用了多年,已经在我的web应用程序中实现基于角色的安全。有关此属性的好处是,.NET JIT编译器完成所有的编织你的背景,你甚至可以在类级别定义它。在这种情况下,该类型的所有成员将继承该属性和它的安全设置。

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.

当然,它有它的局限性。你的第二个code样品不能使用基于.NET角色的安全属性来实现。我觉得你真的不能来了周围的一些自定义的安全检查,在这种方法中,或调用一些内部安全库。

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

当然你也可以使用一个AOP框架,但你仍然需要编写,将再次拨打您自己的安全层的框架的具体属性。这只会得到有用的时候不必把code里面的尝试,渔获量,最后陈述时,这样的属性将取代多个方法调用,例如。如果你会做一个简单的方法调用,不会有一个方法调用或单个属性IMO太大的区别。

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.

当您返回对象的集合,并希望筛选出当前用户不具有适当权限的所有对象,LINQ EX pression树木就可以派上用场:

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

当你的O / RM支持LINQ通过EX pression树(如NHibernate的,LINQ to SQL和实体框架),你可以写这样的安全方法一次,处处应用它。当然,关于这样做的好处是,查询到你的数据库将永远是最佳的。换句话说,没有更多的记录将被检索比需要

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.

更新(年后):

我用这个属性很长一段时间在我的code基,但几年前,我来到了基于属性的AOP有可怕的负面影响的结论。例如,它阻碍了可测试性。由于安全code为编织正常code,你不能无需冒充合法用户的正常运行单元测试。这是脆,不应该是单元测试(单元测试本身违反了单一职责原则)的关注。除此之外,它迫使你垃圾与该属性的code碱基。

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.

因此​​,而不是使用 PrincipalPermissionAttribute ,我宁愿通过包装code用的装饰。这使我的应用程序更加灵活,更容易测试。我已经写了几篇文章关于这项技术在过去几年(例如这一和这个)。

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).