2010-06-09 2 views
8

Мы используем ASP.NET с множеством вызовов «Метод страницы» AJAX. WebServices, определенные на странице, вызывают методы из нашего BusinessLayer. Чтобы хакеры не вызывали методы страницы, мы хотим реализовать некоторую безопасность в BusinessLayer.Обеспечьте безопасный метод бизнес-уровня. best practice/best pattern

Мы боремся с двумя разными проблемами.

Первый один:

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, тогда еще каждый раз) Надеюсь, вы получите то, что я имею в виду :-)

+1

Я вижу, что вы некоторое время были на СО. Тем не менее, я предлагаю вам оставить теги ([.net/C#]) вне заголовка. Пусть они остаются в тегах. Кроме того, «Привет» и «Спасибо», если они подходят для дискуссионного форума, не подходят для сайта Q & A, такого как SO. Благодарю. –

+0

@John ok. Спасибо за подсказки. – gsharp

ответ

9

Пользователь @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); 
} 

Конечно, вы можете использовать АОП, но вы все равно придется написать определенный атрибут рамки, которые будут снова вызывать свой собственный уровень безопасности. Это было бы полезно только тогда, когда такой атрибут заменил бы вызовы нескольких методов, например, когда нужно было бы вводить код внутри 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), вы можете написать такой метод безопасности один раз и применить его повсюду. Конечно, приятная вещь в том, что запрос к вашей базе данных всегда будет оптимальным. Другими словами, больше записей не будет получено, чем необходимо.

UPDATE (года):

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

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

0

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

Схема может быть что-то вроде этого

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

любые образцы/литература? – gsharp

+1

Я согласен поставить безопасность на уровне приложения, а не на уровне «Framework», как другие ответы. Что делать, если роли динамичны? –

2

One «лучшей практики» заключается в реализации безопасности аспект. Это защищает правила безопасности от основной бизнес-логики, избегая жесткого кодирования и упрощая изменение правил безопасности в разных средах.

В приведенной ниже статье перечислены 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 цента. –

+0

@Mike - атрибуты являются вашими собственными, поэтому я не вижу, как это привязано к любой структуре. Это детализация реализации - декларативная безопасность, а не написание кода. Вы по-прежнему свободны писать код, но сами вводите код в бизнес-объекты, что, по словам OP, он хочет избежать. Когда атрибуты помещаются в бизнес-объекты, они все еще «отделены» от кода, то есть легко идентифицируются. Это не так, если вы делаете проверки безопасности как код и помещаете это в бизнес-логику. – mdma

+0

Привет, ну, я вижу, что это жесткое кодирование. Вот почему я сказал «рамки» извините. Что делать, если роли динамичны? Я бы создал объекты безопасности, например, как объекты «Пользователь», поскольку они являются частью системы, как и все остальное. –

Смежные вопросы