web-dev-qa-db-fra.com

Authentification, autorisation, gestion des utilisateurs et des rôles et sécurité générale dans .NET

J'ai besoin de savoir comment mettre en œuvre la sécurité générale pour une application C #. Quelles options ai-je à cet égard? Je préférerais utiliser un framework existant s'il répond à mes besoins - je ne veux pas réinventer la roue.

Mes exigences sont les suivantes:

  • l'authentification usuelle par nom d'utilisateur/mot de passe
  • gestion des utilisateurs - attribuer des autorisations aux utilisateurs
  • gestion des rôles - attribuer des utilisateurs à des rôles, attribuer des autorisations aux rôles
  • autorisation des utilisateurs en fonction de leur nom d'utilisateur et de leur rôle

Je recherche un framework/bibliothèque libre/open-source qui a été testé et utilisé par la communauté .Net.

Mon application adopte une approche client/serveur, le serveur s'exécutant en tant que service Windows, se connectant à une base de données SQL Server. La communication entre le client et le serveur se fera via WCF.

Une autre chose qui est importante est que je dois être en mesure d'attribuer des autorisations d'utilisateurs ou de rôles spécifiques pour afficher/mettre à jour/supprimer une entité spécifique, qu'il s'agisse d'un client, d'un produit, etc. Jack peut afficher un certain 3 clients sur 10, mais ne met à jour que les détails des clients Microsoft, Yahoo et Google, et ne peut supprimer que Yahoo.

31
Saajid Ismail

Pour une sécurité grossière, vous pouvez trouver le code principal intégré utile; l'objet utilisateur (et leurs rôles) sont contrôlés dans .NET par le "principal", mais utilement le runtime lui-même peut appliquer cela.

L'implémentation d'un principal peut être définie par l'implémentation, et vous pouvez généralement injecter la vôtre; par exemple dans WCF .

Pour voir le runtime imposant l'accès grossier (c.-à-d. Quelle fonctionnalité peut être accédée, mais sans s'y limiter à quelles données spécifiques ):

static class Roles {
    public const string Administrator = "ADMIN";
}
static class Program {
    static void Main() {
        Thread.CurrentPrincipal = new GenericPrincipal(
            new GenericIdentity("Fred"), new string[] { Roles.Administrator });
        DeleteDatabase(); // fine
        Thread.CurrentPrincipal = new GenericPrincipal(
            new GenericIdentity("Barney"), new string[] { });
        DeleteDatabase(); // boom
    }

    [PrincipalPermission(SecurityAction.Demand, Role = Roles.Administrator)]
    public static void DeleteDatabase()
    {
        Console.WriteLine(
            Thread.CurrentPrincipal.Identity.Name + " has deleted the database...");
    }
}

Cependant, cela n'aide pas avec l'accès fin (c'est-à-dire "Fred peut accéder au client A mais pas au client B").


Additionnel; Bien sûr, pour une granularité fine, vous pouvez simplement vérifier les rôles requis lors de l'exécution, en cochant IsInRole sur le principal:

static void EnforceRole(string role)
{
    if (string.IsNullOrEmpty(role)) { return; } // assume anon OK
    IPrincipal principal = Thread.CurrentPrincipal;
    if (principal == null || !principal.IsInRole(role))
    {
        throw new SecurityException("Access denied to role: " + role);
    }
}
public static User GetUser(string id)
{
    User user = Repository.GetUser(id);
    EnforceRole(user.AccessRole);
    return user;
}

Vous pouvez également écrire vos propres objets principal/identité qui effectuent des tests paresseux/mise en cache des rôles, plutôt que d'avoir à les connaître tous à l'avance:

class CustomPrincipal : IPrincipal, IIdentity
{
    private string cn;
    public CustomPrincipal(string cn)
    {
        if (string.IsNullOrEmpty(cn)) throw new ArgumentNullException("cn");
        this.cn = cn;
    }
    // perhaps not ideal, but serves as an example
    readonly Dictionary<string, bool> roleCache =
        new Dictionary<string, bool>();
    public override string ToString() { return cn; }
    bool IIdentity.IsAuthenticated { get { return true; } }
    string IIdentity.AuthenticationType { get { return "iris scan"; } }
    string IIdentity.Name { get { return cn; } }
    IIdentity IPrincipal.Identity { get { return this; } }

    bool IPrincipal.IsInRole(string role)
    {
        if (string.IsNullOrEmpty(role)) return true; // assume anon OK
        lock (roleCache)
        {
            bool value;
            if (!roleCache.TryGetValue(role, out value)) {
                value = RoleHasAccess(cn, role);
                roleCache.Add(role, value);
            }
            return value;
        }
    }
    private static bool RoleHasAccess(string cn, string role)
    {
        //TODO: talk to your own security store
    }
}
33
Marc Gravell

ma réponse dépend probablement de la réponse à cette question: S'agit-il d'une application d'entreprise qui vit dans un réseau avec Active Directory? =

SI la réponse est oui, voici les étapes que je fournirais:

1) Créez des groupes globaux pour votre application, dans mon cas, j'avais un groupe APPUSER et un groupe APPADMIN.

2) Faites en sorte que votre serveur SQL soit accessible en mode AUTHENTIFICATION MIXTE, puis affectez votre ou vos groupes APPUSER en tant que LOGIN SQL SERVER à votre base de données avec les droits CRUD appropriés sur votre ou vos bases de données, et assurez-vous que vous accédez le serveur SQL avec Trusted Connection = True dans votre chaîne de connexion.

À ce stade, votre magasin AD sera responsable de l'authentification. Étant donné que vous accédez à l'application via une CONNEXION DE CONFIANCE, elle transmettra l'identité du compte exécutant l'application au serveur SQL.

Maintenant, pour AUTORISATION (c'est-à-dire dire à votre application ce que l'utilisateur connecté est autorisé à faire), il suffit d'interroger AD pour une liste de groupes dont l'utilisateur connecté est membre. Ensuite, vérifiez les noms de groupe appropriés et créez votre interface utilisateur en fonction de l'appartenance de cette façon.

Le fonctionnement de mes applications est donc:

  1. Au lancement de l'application, les identifiants sont basés sur l'utilisateur connecté, c'est l'aspect principal de l'authentification (c'est-à-dire qu'ils peuvent se connecter donc ils existent)
  2. J'obtiens tous les groupes pour l'identité Windows en question
  3. Je vérifie le groupe d'utilisateurs standard - si ce groupe n'existe pas pour l'identité Windows en question, c'est un échec d'authentification
  4. Je recherche le groupe d'utilisateurs ADMIN - Avec cela existant dans les groupes d'utilisateurs, je modifie l'interface utilisateur pour autoriser l'accès aux composants d'administration
  5. Afficher l'interface utilisateur

J'ai alors soit un objet PRINCIPLE avec les droits déterminés/etc dessus, soit j'utilise des variables GLOBAL auxquelles je peux accéder pour déterminer l'interface utilisateur appropriée lors de la création de mes formulaires (c'est-à-dire si mon utilisateur n'est pas membre du groupe ADMIN, alors je 'd cacher tous les boutons DELETE).

Pourquoi est-ce que je suggère cela?

C'est une question de déploiement.

D'après mon expérience, la plupart des applications d'entreprise sont déployées par des ingénieurs réseau plutôt que par des programmeurs.Par conséquent, il est logique de confier l'authentification/l'autorisation à AD, car c'est là que les gars du réseau vont lorsque vous discutez de l'authentification/autorisation.

De plus, lors de la création de nouveaux utilisateurs pour le réseau, un ingénieur réseau (ou toute personne responsable de la création de nouveaux utilisateurs réseau) est plus apte à se souvenir d'effectuer des affectations de groupe alors qu'il est IN AD que le fait qu'il doit entrer dans un douzaines d'applications pour analyser les attributions d'autorisation.

Cela aide avec le labyrinthe d'autorisations et de droits que les nouvelles embauches doivent être accordées ou ceux qui quittent l'entreprise doivent être refusés et cela maintient l'authentification et l'autorisation dans le référentiel central auquel il appartient (c'est-à-dire dans AD @ au niveau du contrôleur de domaine).

3
Stephen Wrighton

Regardez dans fournisseurs d'adhésion d'ASP.NET . Je ne pense pas que le SQLMembershipProvider prêt à l'emploi fonctionnera dans votre cas, mais il est assez facile de lancer votre propre fournisseur.

3
MyItchyChin

Je voudrais jeter un oeil à quelque chose comme CSLA.net: Expert C # 2008 Business Objects

Il devrait fournir tout ce dont vous avez besoin.

2
Chris Andrews

WCF a des fonctionnalités riches liées à la sécurité qui fournissent à la fois l'autorisation et l'authentification. En détails ici: http://msdn.Microsoft.com/en-us/library/ms735093.aspx

1
Ray

Je pense que vous examinez quelques problèmes distincts ici - ce n'est pas un accident que la plupart des systèmes de sécurité séparent l'authentification et l'autorisation.

Pour l'authentification, la plus grande question est la logistique. Ou, y a-t-il un endroit logique pour que ces utilisateurs vivent, que ce soit localement dans l'application, dans Active Directory, dans un autre magasin LDAP ou même dans une autre application. Exactement là où cela n'a pas d'importance - nous avons juste besoin de pouvoir identifier solidement les utilisateurs et de préférence faire de cette tâche le problème de quelqu'un d'autre. En fin de compte, vous avez juste besoin d'un identifiant unique et le confort que Bob de la comptabilité est en fait Bob de la comptabilité.

L'autorisation est la partie la plus intéressante du problème ici. Je pense que si c'est vraiment précis, vous voulez vraiment gérer cela entièrement dans votre application, peu importe d'où viennent les utilisateurs. Marc Gravell a vraiment trouvé un bon moyen de modéliser au moins une partie de cela - utiliser une implémentation personnalisée d'IPrincipal et de PrincipalPermission pour gérer les choses est une façon très propre de commencer. Au-delà de cela, vous pouvez utiliser des techniques comme celle-ci pour prendre des décisions d'autorisation plus complexes d'une manière plutôt propre.

0
Wyatt Barnett

J'utiliserais le terme "RBAC" (système de contrôle d'accès basé sur les rôles) comme solution à toutes vos exigences.

Je n'entrerai pas dans les détails pour expliquer ici `` RBAC '', mais je le décrirais brièvement comme suit:

Il contient essentiellement 3 fonctionnalités.

1) Authentification - Il confirme l'identité de l'utilisateur. Habituellement, cela se fait via des comptes d'utilisateurs et des mots de passe ou des informations d'identification.

2) Autorisation - Il définit ce que l'utilisateur peut et ne peut pas faire dans une application. Ex. La "modification de la commande" est autorisée, mais la "création d'une nouvelle commande" n'est pas autorisée.

3) Audit des actions des utilisateurs sur les applications. - Il garde une trace des actions de l'utilisateur sur les applications, ainsi que de qui a accordé quel accès à quels utilisateurs?

vous pouvez vérifier RBAC sur wiki ici.

https://en.wikipedia.org/wiki/Role-based_access_control

Maintenant, en ce qui concerne la réponse à vos besoins, l'une des solutions possibles consiste à étendre l'adhésion à ASP.NET selon vos besoins.

Et en ce qui concerne, un cadre prêt à l'emploi, je recommanderais VisualGuard pour lequel je travaille, vous devriez vérifier cela, Il fait tout ce dont vous avez besoin très facilement, et le plus important est, Il gère tous vos utilisateurs, rôles, autorisations et applications via la console d'administration centrale, et pour définir les autorisations, les administrateurs n'ont pas besoin des connaissances du développeur, c'est-à-dire qu'il/elle peut créer des restrictions sur les activités via l'interface utilisateur.

vous pouvez également consulter cet article pour mieux comprendre les autorisations et le système basé sur les rôles.

http://www.visual-guard.com/FR/net-powerbuilder-application-security-authentication-permission-access-control-rbac-articles/dotnet-security-article-ressources/role-based- contrôle d'accès-source_soforum.html

0
Kunal Khatri