Estoy tratando de crear un marco ACL flexible en Java para mi aplicación.
Muchos marcos de ACL se basan en una lista blanca de reglas, donde una regla tiene la forma de propietario: acción: recurso . Por ejemplo,
- "JOHN puede VER el recurso FOOBAR-1"
- "MARY puede VER el recurso FOOBAR-1"
- "MARY puede EDITAR el recurso FOOBAR-1"
Esto es atractivo porque las reglas se pueden serializar / persistir fácilmente en una base de datos. Pero mi aplicación tiene una lógica empresarial compleja. Por ejemplo,
- "Todos los usuarios en el departamento 1 con más de 5 años de antigüedad pueden VER el recurso FOOBAR-1, de lo contrario no están autorizados"
- "Todos los usuarios del departamento 2, si la fecha es posterior al 15/03/2016, pueden VER el recurso FOOBAR-2, de lo contrario no están autorizados"
Pensándolo bien, sería una pesadilla diseñar un esquema de base de datos que pudiera manejar reglas infinitamente complejas como estas. Por lo tanto, parece que tendría que "hornearlos" en la aplicación compilada, evaluarlos para cada usuario y luego producir propietario: acción: reglas de recursos como resultado de la evaluación. Quiero evitar incluir la lógica en la aplicación compilada.
Entonces, estaba pensando en representar una regla en forma de predicado : acción: recurso , donde el predicado es una expresión booleana que determina si un usuario está permitido. El predicado sería una cadena de una expresión de JavaScript que podría ser evaluada por el motor Rhino de Java. Por ejemplo,
return user.getDept() == 1 && user.seniority > 5;
Al hacerlo, los predicados podrían fácilmente persistir en la base de datos.
¿Es esto inteligente ? ¿Es esto descuidado ? ¿Esto es un truco ? ¿Está sobre-diseñado ? ¿Es esto seguro (aparentemente, Java puede proteger el motor Rhino).
fuente
Respuestas:
Conectar datos dinámicos a un intérprete de su lenguaje de implementación suele ser una mala idea, ya que aumenta el potencial de corrupción de datos a un potencial de adquisición de aplicaciones maliciosas. En otras palabras, está haciendo todo lo posible para crear una vulnerabilidad de inyección de código .
Su problema puede resolverse mejor mediante un motor de reglas o tal vez un lenguaje de dominio específico (DSL) . Mire esos conceptos, no hay necesidad de reinventar la rueda.
fuente
==
lugar de===
en tu ejemplo. ¿Realmente desea proporcionar la integridad de turing cuando todas las reglas deberían terminar definitivamente? En lugar de saltar a través de los aros para asegurarte de que todas las interacciones entre Java y JavaScript sean kosher, ¿por qué no escribes un simple analizador e intérprete como sugirió Kilian? Será mucho más fácil adaptarlo a sus necesidades y asegurarlo. Usa ANTLR o algo así.while (true) ;
Hice esto y te recomiendo que no lo hagas.
Lo que hice fue escribir toda la lógica de negocios en Lua, y almacené ese script Lua en una base de datos. Cuando mi aplicación se inicia, se carga y ejecuta el script. De esa manera podría actualizar la lógica de negocios de mi aplicación sin distribuir un nuevo binario.
Invariablemente descubrí que siempre necesitaba actualizar el binario al hacer cambios. Algunos cambios estaban en el script de Lua, pero invariablemente tenía una lista de cambios que debían hacerse, por lo que casi siempre terminaba teniendo que hacer algunos cambios en el binario y algunos cambios en el script de Lua. Mi imaginación de que podría evitar distribuir binarios todo el tiempo simplemente no funcionó.
Lo que encontré mucho más útil fue facilitar la distribución de binarios. Mi aplicación busca automáticamente actualizaciones al inicio, descargas e instala cualquier actualización. Por lo tanto, mis usuarios siempre están en los últimos binarios que he introducido. Casi no hay diferencia entre un cambio en el binario y un cambio en los scripts. Si lo volviera a hacer, me esforzaría aún más para que la actualización sea perfecta.
fuente
No quisiera que la base de datos contenga código. Pero puede hacer algo similar haciendo que la base de datos contenga nombres de funciones y luego usando la reflexión para llamarlos. Cuando agrega una nueva condición, debe agregarla a su código y a su base de datos, pero puede combinar condiciones y parámetros que se les pasan para crear evaluaciones bastante complejas.
En otras palabras, si tiene departamentos numerados, sería fácil tener una verificación UserDepartmentIs y una verificación TodayIsAfter y luego combinarlas para tener un Departamento = 2 y Today> 15/03/2016. Si luego desea tener una comprobación TodayIsBefore para poder finalizar la fecha del permiso, debe escribir la función TodayIsBefore.
No he hecho esto para los permisos de usuario, pero lo he hecho para la validación de datos, pero debería funcionar.
fuente
XACML es la solución que realmente estás buscando. Es un tipo de motor de reglas que se centra únicamente en el control de acceso. XACML, un estándar definido por OASIS, define tres partes:
La arquitectura es la siguiente:
Así es como se ve su primer caso de uso:
Su segundo caso de uso sería:
Puede combinar ambos casos de uso en una sola política utilizando referencias:
¡Y tu estas listo!
Puede leer más sobre XACML y ALFA en:
fuente
Lo que realmente quieres aquí es XACML . Prácticamente te da exactamente lo que quieres. No necesariamente tiene que implementar la arquitectura completa con todos los roles completamente separados ... si solo tiene una sola aplicación, probablemente pueda salirse con la integración de PDP y PEP en su aplicación con balana y el PIP es lo que sea su base de datos de usuario existente es
Ahora, en cualquier lugar de su aplicación necesita autorizar algo, crea una solicitud XACML que tiene el usuario, la acción y el contexto, y el motor XACML tomará la decisión en función de los archivos de política XACML que ha escrito. Estos archivos de políticas se pueden guardar en la base de datos o en el sistema de archivos, o donde desee mantener la configuración. Axiomatics tiene una buena alternativa a la representación XML XACML llamada ALFA que es un poco más fácil de leer que el XML sin procesar, y un complemento Eclipse para generar XML XACML a partir de políticas ALFA.
fuente
Lo hicimos en mi empresa actual y estamos muy contentos con los resultados.
Nuestras expresiones están escritas en js, e incluso las usamos para restringir los resultados que los usuarios pueden obtener al consultar ElasticSearch.
El truco es asegurarse de que haya suficiente información disponible para tomar la decisión, de modo que realmente pueda escribir cualquier permiso que desee sin cambios de código, pero al mismo tiempo mantenerlo rápido.
No estamos realmente preocupados con los ataques de inyección de código, ya que los permisos están escritos por aquellos que no tienen necesidad de atacar el sistema. Y lo mismo se aplica a los ataques de DOS como el
while(true)
ejemplo. Los administradores del sistema no tienen necesidad de hacer eso, simplemente podrían eliminar los permisos de todos ...Actualizar:
Algo como XACML parece ser mejor como un punto central de administración de autenticación para una organización. Nuestro caso de uso es ligeramente diferente en el sentido de que nuestros clientes normalmente no tienen un departamento de TI para ejecutar todo eso. Necesitábamos algo autónomo pero tratamos de preservar la mayor flexibilidad posible.
fuente