Сделайте метод бизнес-уровня безопасным.лучшая практика / лучшая модель - PullRequest
9 голосов
/ 09 июня 2010

Мы используем ASP.NET с большим количеством вызовов метода страниц AJAX. Веб-сервисы, определенные на странице, вызывают методы из нашего BusinessLayer. Чтобы не дать хакерам вызвать методы страницы, мы хотим реализовать некоторую защиту в 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 if then) Я надеюсь, вы понимаете, что я имею в виду: -)

Ответы [ 3 ]

9 голосов
/ 16 июня 2010

Пользователь @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). Я уже несколько лет использую его для реализации безопасности на основе ролей в моих веб-приложениях. Хорошая вещь об этом атрибуте состоит в том, что компилятор .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 поддерживает LINQ через деревья выражений (такие как NHibernate, LINQ to SQL и Entity Framework), вы можете написать такой метод защиты один раз и применять его везде. Конечно, приятно то, что запрос к вашей базе данных всегда будет оптимальным. Другими словами, не будет извлечено больше записей, чем необходимо.

ОБНОВЛЕНИЕ (годы спустя):

Я долгое время использовал этот атрибут в своей кодовой базе, но несколько лет назад я пришел к выводу, что AOP на основе атрибутов имеет ужасные недостатки. Например, это мешает тестированию. Поскольку код безопасности сплетен с обычным кодом, вы не можете запускать обычные модульные тесты без необходимости выдавать себя за действительного пользователя. Это хрупко и не должно быть предметом юнит-теста (сам юнит-тест нарушает принцип единой ответственности). Кроме того, он заставляет вас засорять вашу кодовую базу этим атрибутом.

Таким образом, вместо использования PrincipalPermissionAttribute я предпочитаю сквозные вопросы, такие как безопасность, заключая код в декораторы . Это делает мое приложение намного более гибким и намного проще для тестирования. За последние несколько лет я написал несколько статей об этой технике (например, , этот и , этот ).

2 голосов
/ 13 июня 2010

Одной из "лучших практик" является реализация аспекта безопасности. Это позволяет отделить правила безопасности от основной бизнес-логики, избегая жесткого кодирования и облегчая изменение правил безопасности в различных средах.

В статье ниже перечислены 7 способов реализации аспектов и сохранения кода отдельно. Один простой подход, который не меняет интерфейс вашей бизнес-логики, - это использование прокси. Это предоставляет тот же интерфейс, что и у вас в настоящее время, но позволяет альтернативную реализацию, которая может украшать существующую реализацию. Требования безопасности могут быть введены в этот интерфейс, используя либо жесткое кодирование, либо пользовательские атрибуты. Прокси-сервер перехватывает вызовы методов вашего бизнес-уровня и вызывает соответствующие проверки безопасности. Реализация перехвата через прокси подробно описана здесь - Отделение компонентов путем внедрения пользовательских сервисов в цепочку вызовов вашего объекта . Другие подходы АОП приведены в Понимание АОП в .NET .

Вот сообщение на форуме , в котором обсуждается безопасность как аспект, с реализацией с использованием рекомендаций и атрибутов безопасности. Конечный результат

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 голосов
/ 10 июня 2010

Если вы используете SOA, вы можете создать службу безопасности, и каждое действие (метод) будет отправлять свой контекст (UserId, OrderId и т. Д.).Служба безопасности знает о правилах безопасности бизнеса.

Схема может выглядеть примерно так

UI -> Security -> BLL -> DAL
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...