2010-06-09 4 views
8

Nous utilisons ASP.NET avec beaucoup d'appels AJAX "Méthode de page". Les WebServices définis dans la page invoquent des méthodes de notre BusinessLayer. Pour empêcher les pirates d'appeler les méthodes de page, nous souhaitons implémenter une certaine sécurité dans BusinessLayer.Rendre une méthode de la couche métier sécurisée. meilleure pratique/meilleur modèle

Nous sommes aux prises avec deux problèmes différents.

premier:

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

Cette méthode doit être appelée par les utilisateurs autorisés avec le rôle "HR".

seconde:

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

Cette méthode ne doit être appelée par le propriétaire de l'Ordre.

Je sais qu'il est facile de mettre en œuvre la sécurité pour chaque méthode comme:

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

ou

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

Ce que je suis à la recherche est un certain modèle/les meilleures pratiques à mettre en œuvre ce genre de sécurité d'une manière générique (sans coder le si sinon d'autre à chaque fois) J'espère que vous obtenez ce que je veux dire :-)

+1

Je vois que vous avez été sur SO pendant un certain temps. Cependant, je vous suggère de laisser les balises ([.net/C#]) hors du titre. Laissez-les rester dans les tags. En outre, "Bonjour" et "Merci", bien que appropriés pour un forum de discussion, ne sont pas appropriés pour un site Q & A comme SO. Merci. –

+0

@John ok. Merci pour les conseils. – gsharp

Répondre

9

L'utilisateur @mdma décrit un peu à propos de la programmation orientée aspect. Pour cela, vous devrez utiliser une bibliothèque externe (telle que la bonne PostSharp), car .NET n'a pas beaucoup de fonctionnalités AOP. Toutefois, .NET dispose déjà d'un mécanisme AOP pour la sécurité basée sur les rôles, qui peut résoudre une partie de votre problème. Regardez l'exemple suivant de code standard .NET:

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

Le PrincipalPermissionAttribute fait partie de l'espace de noms System.Security.Permissions et fait partie de .NET (depuis la version 1.0 .NET). Je l'utilise depuis des années déjà pour implémenter la sécurité basée sur les rôles dans mes applications web. Une bonne chose à propos de cet attribut est que le compilateur .NET JIT fait tout le tissage pour vous en arrière-plan et vous pouvez même le définir au niveau de la classe. Dans ce cas, tous les membres de ce type hériteront de cet attribut et de ses paramètres de sécurité.

Bien sûr, il a ses limites. Votre deuxième exemple de code ne peut pas être implémenté à l'aide de l'attribut de sécurité basé sur le rôle .NET. Je pense que vous ne pouvez pas vraiment contourner certains contrôles de sécurité personnalisés dans cette méthode, ou appelez une bibliothèque de sécurité interne.

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

Bien sûr, vous pouvez utiliser un cadre de l'AOP, mais vous auriez encore d'écrire un cadre attribut spécifique qui appellera à nouveau votre propre couche de sécurité. Cela ne serait utile que si un tel attribut remplaçait plusieurs appels de méthode, par exemple lorsqu'il fallait mettre du code à l'intérieur de try, catch, finally statements. Lorsque vous effectuez un appel de méthode simple, il n'y aurait pas beaucoup de différence entre un seul appel de méthode ou un seul attribut IMO.

Lorsque vous retournez une collection d'objets et que vous voulez filtrer tous les objets pour lesquels l'utilisateur actuel ne dispose pas des droits appropriés, les arbres d'expression LINQ peuvent être utiles:

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

Lorsque votre O/RM prend en charge LINQ via les arborescences d'expression (telles que NHibernate, LINQ to SQL et Entity Framework). Vous pouvez écrire une telle méthode de sécurité une seule fois et l'appliquer partout. Bien sûr, la bonne chose à ce sujet est que la requête à votre base de données sera toujours optimale. En d'autres termes, plus d'enregistrements seront récupérés que nécessaire.

MISE À JOUR (années plus tard):

J'ai utilisé cet attribut depuis longtemps dans ma base de code, mais plusieurs années, je suis venu à la conclusion que l'attribut base AOP a de terribles inconvénients. Par exemple, il empêche la testabilité. Puisque le code de sécurité est tissé avec du code normal, vous ne pouvez pas exécuter des tests unitaires normaux sans avoir à emprunter l'identité d'un utilisateur valide. Ceci est fragile et ne devrait pas être une préoccupation du test unitaire (le test unitaire viole le Principe de Responsabilité Unique). En plus de cela, il vous oblige à jeter votre base de code avec cet attribut.

Donc, au lieu d'utiliser le PrincipalPermissionAttribute, j'applique plutôt les préoccupations transversales comme la sécurité en enveloppant le code avec decorators. Cela rend mon application beaucoup plus flexible et beaucoup plus facile à tester. J'ai écrit plusieurs articles sur cette technique au cours des dernières années (par exemple this one et this one).

0

Si vous utilisez SOA, vous pouvez créer un service de sécurité, et chaque action (méthode) enverra son contexte (UserId, OrderId etc.). Le service de sécurité connaît les règles de sécurité de l'entreprise.

Scheme peut être quelque chose comme ça

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

des échantillons/de la littérature? – gsharp

+1

Je suis d'accord pour mettre la sécurité au niveau de l'application et non au niveau "Framework" comme les autres réponses. Et si les rôles sont dynamiques? –

2

Une "meilleure pratique" est de mettre en œuvre un aspect de sécurité. Cela permet de séparer les règles de sécurité de la logique métier principale, en évitant le codage en dur et en facilitant la modification des règles de sécurité dans différents environnements.

L'article ci-dessous répertorie 7 façons de mettre en œuvre des aspects et de garder le code séparé. Une approche simple et qui ne change pas votre interface de logique métier consiste à utiliser un proxy. Cela expose la même interface que vous avez actuellement, mais permet une implémentation alternative, qui peut décorer l'implémentation existante. Les exigences de sécurité peuvent être injectées dans cette interface, en utilisant soit des attributs codés en dur, soit des attributs personnalisés. Le proxy intercepte les appels de méthode à votre couche de gestion et appelle les vérifications de sécurité appropriées. La mise en œuvre de l'interception via des proxies est décrite en détail ici - Decouple Components by Injecting Custom Services into your Object's Invocation Chain. D'autres approches AOP sont données dans Understanding AOP in .NET.

Voici un forum post qui traite de la sécurité en tant qu'aspect, avec une implémentation utilisant des conseils et des attributs de sécurité. Le résultat final est

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

Vous pouvez mettre l'attribut directement sur votre méthode d'affaires, couplage serré ou créer un proxy de service avec ces attributs, de sorte que les détails de sécurité sont maintenus séparés.

+0

La solution est trop liée à la charpente à mon avis (par des méthodes de décoration). Je mettrais en œuvre les fonctions de sécurité qui font partie du système car elles ne sont pas aussi éloignées de la logique métier que cela puisse paraître. J'aime la suggestion de proxy si .. mes 2 cents. –

+0

@Mike - les attributs sont les vôtres, donc je ne vois pas comment cela est lié à un framework. Ils constituent un détail d'implémentation - la sécurité déclarative plutôt que l'écriture de code. Vous êtes toujours libre d'écrire du code, mais en mettant le code sur les objets métier eux-mêmes ce que le PO dit qu'il veut éviter. Lorsque les attributs sont placés sur les objets métier, ils sont toujours "séparés" du code, c'est-à-dire facilement identifiables. Ce n'est pas vraiment le cas si vous effectuez les contrôles de sécurité en tant que code et mettez cela dans la logique métier. – mdma

+0

Salut, eh bien je le vois comme c'est hardcoding. C'est pourquoi j'ai dit "cadre" désolé. Et si les rôles sont dynamiques? Je créerais des objets de sécurité comme des objets "Utilisateur" par exemple car ils font partie du système comme tout le reste. –

Questions connexes