Valutazione del codice dinamico in Java: intelligente o sciatta?

30

Sto cercando di creare un framework ACL flessibile in Java per la mia applicazione.

Molti framework ACL sono costruiti su una whitelist di regole, in cui una regola è sotto forma di owner: action: resource . Ad esempio,

  • "JOHN può VISUALIZZARE la risorsa FOOBAR-1"
  • "MARY può VISUALIZZARE la risorsa FOOBAR-1"
  • "MARY può modificare la risorsa FOOBAR-1"

È interessante perché le regole possono essere facilmente serializzate / mantenute su un database. Ma la mia applicazione ha una logica aziendale complessa. Ad esempio,

  • "Tutti gli utenti del dipartimento 1 con più di 5 anni di anzianità possono VISUALIZZARE la risorsa FOOBAR-1, altrimenti non autorizzati"
  • "Tutti gli utenti del dipartimento 2, se la data è successiva al 15/03/2016, possono VISUALIZZARE la risorsa FOOBAR-2, altrimenti non autorizzata"

A prima vista, sarebbe un incubo escogitare uno schema di database che possa gestire regole infinitamente complesse come queste. Pertanto, sembra che avrei bisogno di "infornarli" nell'applicazione compilata, valutarli per ciascun utente e quindi produrre regole proprietario: azione: risorsa come risultato della valutazione. Voglio evitare di cuocere la logica nell'applicazione compilata.

Quindi, stavo pensando di rappresentare una regola sotto forma di predicato : action: resource, dove il predicato è un'espressione booleana che determina se un utente è autorizzato . Il predicato sarebbe una stringa di un'espressione JavaScript che potrebbe essere valutata dal motore di Rhino di Java. Ad esempio,

  • return user.getDept() == 1 && user.seniority > 5;

In tal modo, i predicati potrebbero essere facilmente mantenuti nel database.

Questo è intelligente ? È questo sloppy ? È questo ingannevole ? Questo è troppo ingegnerizzato ? È questo sicuro (a quanto pare, Java può sandbox il motore di Rhino).

    
posta Twittopher 26.03.2015 - 15:08
fonte

6 risposte

37

Convogliare i dati dinamici in un interprete del linguaggio di implementazione è in genere una cattiva idea, poiché aumenta il potenziale di danneggiamento dei dati in un potenziale di acquisizione di applicazioni dannose. In altre parole, si sta andando fuori strada per creare una iniezione di codice vulnerabilità.

Il tuo problema può essere risolto meglio con un motore delle regole o forse un linguaggio specifico del dominio (DSL) . Guarda questi concetti, non c'è bisogno di reinventare la ruota.

    
risposta data 26.03.2015 - 15:14
fonte
44

L'ho fatto e ti consiglio di non farlo.

Quello che ho fatto è stato scrivere tutte le logiche di business in Lua e archiviare quello script Lua in un database. All'avvio dell'applicazione, caricare ed eseguire lo script. In questo modo ho potuto aggiornare la logica di business della mia applicazione senza distribuire un nuovo binario.

Ho sempre riscontrato che dovevo sempre aggiornare il file binario quando apporta modifiche. Alcuni cambiamenti erano nello script Lua, ma avrei sempre avuto un elenco di modifiche che dovevano essere apportate, e così quasi sempre ho dovuto apportare alcune modifiche al binario e alcune modifiche nello script Lua. La mia immaginazione che avrei potuto evitare di distribuire i binari per tutto il tempo semplicemente non è andata a buon fine.

Quello che ho trovato molto più utile è stato facilitare la distribuzione dei binari. La mia applicazione controlla automaticamente gli aggiornamenti all'avvio, scarica e installa qualsiasi aggiornamento. I miei utenti sono quindi sempre sugli ultimi binari che ho spinto. Non c'è quasi nessuna differenza tra un cambiamento nel file binario e un cambiamento negli script. Se l'avessi fatto di nuovo, avrei fatto ancora più sforzo per rendere l'aggiornamento perfetto.

    
risposta data 26.03.2015 - 16:36
fonte
3

Non vorrei che il database contenga il codice. Ma puoi fare qualcosa di simile facendo in modo che il database contenga nomi di funzioni e quindi usando reflection per chiamarli. Quando aggiungi una nuova condizione, devi aggiungerla al tuo codice e al tuo database, ma puoi combinare condizioni e parametri che vengono passati a loro per creare valutazioni abbastanza complesse.

In altre parole, se hai reparti numerati, sarebbe facile avere un controllo UserDepartmentIs e un controllo TodayIsAfter e poi combinarli per avere un Department = 2 e Today > 03/15/2016. Se si desidera avere un controllo TodayIsBefore in modo da poter terminare l'autorizzazione, è necessario scrivere la funzione TodayIsBefore.

Non l'ho fatto per le autorizzazioni degli utenti, ma l'ho fatto per la convalida dei dati, ma dovrebbe funzionare.

    
risposta data 26.03.2015 - 19:40
fonte
2

XACML è la soluzione che stai davvero cercando. È un tipo di motore di regole incentrato solo sul controllo dell'accesso. XACML, uno standard definito da OASIS, definisce tre parti:

  • un'architettura
  • un linguaggio di policy (che è proprio quello che vuoi)
  • uno schema di richiesta / risposta (come si chiede una decisione di autorizzazione)

L'architettura è la seguente:

  • il punto di decisione politica (PDP) è la parte centrale dell'architettura. È il componente che valuta le richieste di autorizzazione in entrata rispetto a un gruppo noto di norme
  • il Policy Enforcement Point (PEP) è la parte di codice che protegge la tua applicazione / API / servizio. PEP intercetta la richiesta aziendale, crea una richiesta di autorizzazione XACML, la invia al PDP, riceve una risposta e impone la decisione all'interno della risposta.
  • il Policy Information Point (PIP) è il componente che può connettere il PDP a fonti esterne di dati, ad es. un LDAP, un database o un servizio web. Il PIP è utile quando il PEP invia una richiesta, ad es. "Alice può visualizzare il documento n. 12?" e il PDP ha una politica che richiede l'età dell'utente. Il PDP chiederà al PIP "dammi l'età di Alice" e sarà quindi in grado di elaborare le politiche.
  • il punto di amministrazione della politica (PAP) è il luogo in cui gestisci l'intera soluzione XACML (definendo attributi, criteri di scrittura e configurazione del PDP).

Eccocomeappareiltuoprimocasod'uso:

/**Allusersindepartment1withover5yearsofsenioritycanVIEWresourceFOOBAR-1,elsenotauthorized**/policydepartmentOne{targetclausedepartment==1applyfirstApplicable/***Allusersindepartment1withover5yearsofsenioritycanVIEWresourceFOOBAR-1,elsenotauthorized*/ruleallowFooBar1{targetclauseresourceId=="FOOBAR-1" and seniority>=5 and actionId=="VIEW"
        permit
    }
    rule denyOtherAccess{
        deny
    }

 }

Il tuo secondo caso d'uso sarebbe:

 /*
  * "All users in department 2, if the date is after 03/15/2016, can VIEW resource FOOBAR-2, else not authorized"
  *  
  */
  policy departmentTwo{
    target clause department == 1
    apply firstApplicable
    rule allowFooBar2{
        target clause resourceId=="FOOBAR-1" and seniority>=5 and currentDate>"2016/03/15":date and actionId=="VIEW"
        permit
    }
    rule denyOtherAccess{
        deny
    }
  }

È possibile combinare entrambi i casi d'uso in una singola politica utilizzando i riferimenti:

  policyset global{
    apply firstApplicable
    departmentOne
    departmentTwo
  }

E hai finito!

Puoi leggere di più su XACML e ALFA da:

risposta data 31.03.2015 - 14:00
fonte
0

Quello che vuoi veramente qui è XACML . Ti dà praticamente quello che vuoi. Non devi necessariamente implementare l'architettura completa con tutti i ruoli completamente separati ... se hai solo una singola applicazione, puoi probabilmente cavartela con l'integrazione di PDP e PEP nella tua app con balana e il PIP è qualunque sia il tuo database utente esistente.

Ora, ovunque nella tua app devi autorizzare qualcosa, crei una richiesta XACML che ha l'utente, l'azione e il contesto, e il motore XACML prenderà la decisione in base ai file delle politiche XACML che hai scritto . Questi file di criteri possono essere conservati nel database o sul filesystem o ovunque si desideri mantenere la configurazione. Axiomatics ha una bella alternativa alla rappresentazione XML XACML chiamata ALFA che è un po 'più facile da leggere rispetto all'XML grezzo e un plugin Eclipse per generare XACML XML dai criteri ALFA.

    
risposta data 28.03.2015 - 05:01
fonte
0

L'abbiamo fatto nella mia attuale compagnia e siamo molto contenti dei risultati.

Le nostre espressioni sono scritte in js, e le usiamo anche per limitare i risultati che gli utenti possono ottenere dall'esperimento di ElasticSearch.

Il trucco consiste nel fare in modo che siano disponibili informazioni sufficienti per prendere la decisione, in modo che tu possa davvero scrivere qualsiasi cosa si desideri senza modifiche al codice, ma allo stesso tempo mantenendola veloce.

Non siamo davvero preoccupati con gli attacchi di iniezione di codice, in quanto le autorizzazioni sono scritte da coloro che non hanno bisogno di attaccare il sistema. Lo stesso vale per gli attacchi DOS come l'esempio while(true) . Gli amministratori del sistema non hanno bisogno di farlo, potrebbero semplicemente rimuovere i permessi di tutti ...

Aggiornamento:

Qualcosa come XACML sembra essere migliore come punto centrale di gestione dell'autorizzazione per un'organizzazione. Il nostro caso d'uso è leggermente diverso in quanto i nostri clienti non hanno tipicamente un reparto IT per eseguire tutto ciò. Avevamo bisogno di qualcosa di autonomo, ma abbiamo cercato di preservare la massima flessibilità possibile.

    
risposta data 09.04.2015 - 12:51
fonte

Leggi altre domande sui tag