J'essaie de créer un cadre ACL flexible en Java pour mon application.
De nombreux frameworks ACL sont construits sur une liste blanche de règles, où une règle est sous la forme propriétaire: action: ressource . Par exemple,
- "JOHN peut VOIR la ressource FOOBAR-1"
- "MARIE peut VOIR la ressource FOOBAR-1"
- "MARIE peut MODIFIER la ressource FOOBAR-1"
Ceci est intéressant car les règles peuvent facilement être sérialisées / conservées dans une base de données. Mais mon application a une logique métier complexe. Par exemple,
- "Tous les utilisateurs du département 1 avec plus de 5 ans d'ancienneté peuvent VOIR la ressource FOOBAR-1, sinon non autorisé"
- "Tous les utilisateurs du département 2, si la date est postérieure au 15/03/2016, peuvent VOIR la ressource FOOBAR-2, sinon non autorisé"
À première vue, ce serait un cauchemar de concevoir un schéma de base de données capable de gérer des règles infiniment complexes comme celles-ci. Par conséquent, il semble que j'aurais besoin de les "cuire" dans l'application compilée, de les évaluer pour chaque utilisateur, puis de produire des règles owner: action: resource à la suite de l'évaluation. Je veux éviter de faire cuire la logique dans l'application compilée.
Donc, je pensais représenter une règle sous forme de prédicat : action: ressource , où le prédicat est une expression booléenne qui détermine si un utilisateur est autorisé. Le prédicat serait une chaîne d'une expression JavaScript qui pourrait être évaluée par le moteur Rhino de Java. Par exemple,
return user.getDept() == 1 && user.seniority > 5;
Ce faisant, les prédicats pourraient facilement être conservés dans la base de données.
Est-ce intelligent ? Est-ce bâclé ? Est-ce gimmicky ? Est-ce trop conçu ? Est-ce sûr (apparemment, Java peut sandboxer le moteur Rhino).
la source
Réponses:
Le transfert de données dynamiques vers un interpréteur de votre langage d'implémentation est généralement une mauvaise idée, car il fait passer le risque de corruption de données à un potentiel de prise de contrôle d'applications malveillantes. En d'autres termes, vous vous efforcez de créer une vulnérabilité d' injection de code .
Votre problème peut être mieux résolu par un moteur de règles ou peut-être un langage spécifique au domaine (DSL) . Recherchez ces concepts, il n'est pas nécessaire de réinventer la roue.
la source
==
au lieu de===
dans votre exemple. Voulez-vous vraiment fournir une complétude complète lorsque toutes les règles devraient sans doute toujours se terminer? Au lieu de sauter à travers des cerceaux pour vous assurer que toutes les interactions entre Java et JavaScript sont casher, pourquoi n'écrivez-vous pas simplement un simple analyseur et interprète comme Kilian l'a suggéré? Il sera beaucoup plus facile de s'adapter à vos besoins et de le sécuriser. Utilisez ANTLR ou quelque chose.while (true) ;
Je l'ai fait et je vous recommande de ne pas le faire.
Ce que j'ai fait, c'est d'écrire toute la logique métier dans Lua et de stocker ce script Lua dans une base de données. Au démarrage de mon application, elle chargeait et exécutait le script. De cette façon, je pouvais mettre à jour la logique métier de mon application sans distribuer un nouveau binaire.
J'ai toujours constaté que j'avais toujours besoin de mettre à jour le binaire lors des modifications. Certaines modifications étaient dans le script Lua, mais j'avais invariablement une liste des modifications qui devaient être apportées, et donc je finissais presque toujours par devoir apporter des modifications au binaire et des modifications au script Lua. Mon imagination que je pouvais éviter de distribuer des binaires tout le temps ne s'est tout simplement pas concrétisée.
Ce que j'ai trouvé beaucoup plus utile était de faciliter la distribution des binaires. Mon application recherche automatiquement les mises à jour au démarrage, télécharge et installe toute mise à jour. Mes utilisateurs sont donc toujours sur les derniers binaires que j'ai poussés. Il n'y a presque aucune différence entre un changement dans le binaire et un changement dans les scripts. Si je recommençais, je ferais encore plus d'efforts pour rendre la mise à jour transparente.
la source
Je ne voudrais pas que la base de données contienne du code. Mais vous pouvez faire quelque chose de similaire en faisant en sorte que la base de données contienne des noms de fonction, puis en utilisant la réflexion pour les appeler. Lorsque vous ajoutez une nouvelle condition, vous devez l'ajouter à votre code et à votre base de données, mais vous pouvez combiner des conditions et des paramètres qui leur sont transmis pour créer des évaluations assez complexes.
En d'autres termes, si vous avez des départements numérotés, il serait facile d'avoir un contrôle UserDepartmentIs et un contrôle TodayIsAfter puis de les combiner pour avoir un Department = 2 et Today> 03/15/2016. Si vous souhaitez ensuite avoir une vérification TodayIsBefore afin de pouvoir terminer la date de l'autorisation, vous devez écrire la fonction TodayIsBefore.
Je ne l'ai pas fait pour les autorisations utilisateur, mais je l'ai fait pour la validation des données, mais cela devrait fonctionner.
la source
XACML est la solution que vous recherchez vraiment. Il s'agit d'un type de moteur de règles qui se concentre uniquement sur le contrôle d'accès. XACML, une norme définie par OASIS, définit trois parties:
L'architecture est la suivante:
Voici à quoi ressemble votre premier cas d'utilisation:
Votre deuxième cas d'utilisation serait:
Vous pouvez combiner les deux cas d'utilisation en une seule stratégie à l'aide de références:
Et tu as fini!
Vous pouvez en savoir plus sur XACML et ALFA à partir de:
la source
Ce que vous voulez vraiment ici, c'est XACML . Cela vous donne à peu près exactement ce que vous voulez. Vous n'avez pas nécessairement à implémenter l'architecture complète avec tous les rôles complètement séparés ... si vous n'avez qu'une seule application, vous pouvez probablement vous en sortir en intégrant le PDP et le PEP dans votre application avec balana et le PIP est tout votre base de données utilisateur existante est.
Maintenant, n'importe où dans votre application, vous devez autoriser quelque chose, vous créez une demande XACML qui a l'utilisateur, l'action et le contexte, et le moteur XACML prendra la décision en fonction des fichiers de stratégie XACML que vous avez écrits. Ces fichiers de stratégie peuvent être conservés dans la base de données ou sur le système de fichiers, ou là où vous souhaitez conserver la configuration. Axiomatics a une belle alternative à la représentation XML XACML appelée ALFA qui est un peu plus facile à lire que le XML brut, et un plugin Eclipse pour générer du XML XACML à partir des politiques ALFA.
la source
Nous l'avons fait dans mon entreprise actuelle et nous sommes très satisfaits des résultats.
Nos expressions sont écrites en js, et nous les utilisons même pour restreindre les résultats que les utilisateurs peuvent obtenir en interrogeant ElasticSearch.
L'astuce consiste à s'assurer que suffisamment d'informations sont disponibles pour prendre la décision, afin que vous puissiez vraiment écrire ce que vous voulez sans changer de code, mais en même temps en le gardant rapide.
Nous ne sommes pas vraiment inquiets des attaques par injection de code, car les autorisations sont écrites par ceux qui n'ont pas besoin d'attaquer le système. Et la même chose s'applique aux attaques DOS comme dans l'
while(true)
exemple. Les administrateurs du système n'ont pas besoin de le faire, ils peuvent simplement supprimer les autorisations de tout le monde ...Mise à jour:
Quelque chose comme XACML semble être meilleur en tant que point central de gestion d'authentification pour une organisation. Notre cas d'utilisation est légèrement différent en ce que nos clients n'ont généralement pas de service informatique pour gérer tout cela. Nous avions besoin de quelque chose de autonome, mais nous avons essayé de conserver autant de flexibilité que possible.
la source