MokaByte Numero 23  -  Ottobre 98

Un Filtro Basato su Regole per Applet Java
 



 

Una delle caratteristiche piu' interessanti di Java e' il suo modello di sicurezza, ed e' probabilmente questo uno dei motivi principali per cui ha riscosso un enorme successo nell'ambito delle reti, fino a diventare linguaggio "ufficiale" per Internet. Nonostante l'eccellente livello di protezione offerto dalle macchine virtuali Java, e' stato provato che e' possibile effettuare attacchi di vario tipo sfruttando i cosiddetti bug, ovvero errori di progetto o di codifica, presenti nelle varie implementazioni.
Questo problema, di grande attualita' nel campo della sicurezza Internet, viene affrontato in quest'articolo in cui viene presentata una soluzione innovativa basata su un filtro di applet che puo' essere utilizzato sia all'interno di un firewall che di una macchina virtuale Java.



 
 
 
 

Introduzione
Sin dalle prime fasi di progetto,  gli aspetti di sicurezza di Java sono stati attentamente tenuti in considerazione. Infatti Java e' uno dei pochi linguaggi che nasce con un sofisticato modello di sicurezza che lo ha poi reso adatto alla scrittura di applet da inviare e eseguire sui browser degli utenti senza che cio' potesse costituire un pericolo per la loro sicurezza. Se un'applet tentasse di effettuare un'operazione "pericolosa" sul sistema ospite, come ad esempio la cancellazione di un file, violerebbe la restrittiva politica di sicurezza imposta per le applet. In questo caso la macchina virtuale non eseguirebbe l'operazione e verrebbe sollevata un'eccezione.

Il modello di sicurezza per le applet Java e' realizzato tramite tre componenti della macchina virtuale:

In questo modo viene creato un ambiente ristretto d'esecuzione all'interno del quale l'applet non puo' accedere a risorse di sistema quali il filesystem e i dispositivi hardware. Qualsiasi altro accesso alle risorse avviene sempre tramite determinati metodi e mai direttamente. L'applet, infine, non puo' accedere direttamente alla memoria, cambiare il proprio codice o eseguire conversioni di tipo non permesse dalla semantica del linguaggio.

Bisogna pero' considerare che una delle modalita' d'attacco piu' utilizzate dagli hacker e' lo sfruttamento dei particolari bug che possono essere utilizzati per ottenere un accesso non autorizzato alle risorse. I sistemi di tipo UNIX, ad esempio, sono stati per anni (e sono ancora) nel mirino degli hacker che sfruttano bug in particolari programmi, detti "di tipo setuid", per acquisire privilegi amministrativi sul sistema attaccato, e quindi eseguire qualsiasi tipo di operazione non autorizzata.

Nonostante l'accuratezza con cui e' stato considerato l'aspetto sicurezza, anche Java si e' dimostrato vulnerabile sotto questo punto di vista. Sono stati infatti scoperti diversi bug nelle varie implementazioni della macchina virtuale che permettevano di aprirsi un varco nel rigido modello di sicurezza imposto dal browser e portare a termine un attacco. Se si pensa al fatto che le applet sui siti con un elevato numero di accessi vengono eseguite su svariate migliaia di macchine, si capisce che il problema e' piuttosto serio e non puo' essere assolutamente trascurato. Ad amplificare il problema c'e' anche il fatto che con la diffusione di Internet le informazioni relative allo sfruttamento di un bug vengono scambiate con una facilita' incredibile: esistono siti che spiegano passo dopo passo come portare avanti un attacco e addirittura offrono la possibilita' di prelevare applet di questo tipo pronte da utilizzare. La piattaforma Java, inoltre, e' in costante evoluzione: vengono continuamente aggiunte nuove librerie, sia dalla casa madre che da altri produttori (si pensi, ad esempio, alla Microsoft che sta portando avanti uno sviluppo della piattaforma orientato ai sistemi Windows, che permette di usarne gran parte delle funzionalita'). Per questo e' molto probabile che in futuro vengano alla luce altri bug nascosti nelle migliaia di linee di codice del runtime, magari anche piu' pericolosi di quelli attualmente scoperti.

Per fronteggiare il problema i principali produttori di macchine virtuali Java si sono impegnati a risolvere problemi di questo tipo nel piu' breve tempo possibile dopo che sono stati scoperti, distribuendo una versione aggiornata della macchina virtuale nella quale il problema non sia presente.

Cio' non risolve completamente il problema, per vari motivi. Innanzitutto la maggior parte degli utenti non segue gli sviluppi in materia di sicurezza della macchina virtuale nel proprio browser. Anzi, in generale sono piuttosto restii ad aggiornare il proprio browser (esistono molti utenti che utilizzano versioni molto vecchie dei piu' popolari browser). Inoltre, esiste un periodo di tempo tra la scoperta del bug e la distribuzione della macchina virtuale aggiornata che puo' essere di alcuni giorni o addirittura di alcune settimane: in questo periodo gli utenti a conoscenza del problema devono scegliere se rischiare un attacco o disabilitare completamente la propria macchina virtuale, rinunciando completamente a tutti i vantaggi della tecnologia Java.

La soluzione proposta in questo articolo, realizzata in forma prototipale presso la Fondazione Ugo Bordoni di Roma, rappresenta un passo avanti un questa direzione. Essa consiste in un filtro basata sull'analisi statica del contenuto delle applet rispetto ad un insieme di regole che permettono di scoprire e bloccare applet potenzialmente ostili, ovvero qulle che potrebbero contenere del codice che tenta di sfruttare un bug della macchina virtuale per un attacco. Il filtro e' stato realizzato in forma modulare per poter essere inserito all'interno di una macchina virtuale Java o come plug-in per un firewall.

Filtraggio delle Applet
La politica seguita dal filtro di applet viene impostata in un file di configurazione contenente un insieme di regole. Una regola e' composta da uno o piu' criteri. Vediamo un esempio di regola:

    RULE example
        STOP java.net:Socket
        ALLOW java.net:Socket.getInetAddress

"example" e' un nome mnemonico dato alla regola per identificarla. Serve ad identificare la regola la cui violazione ha fermato una certa applet;
"STOP java.net:Socket" e' il primo criterio della regola "example". Con questo criterio, di tipo STOP, vengono fermate tutte le applet che contengono un riferimento alla classe Socket del package java.net. Per "riferimento" si intendono anche le invocazioni dei relativi metodi e delle eventuali variabili membro.
Il criterio "ALLOW java.net:Socket.getInetAddress", essendo un criterio di tipo ALLOW, permette di far passare tutte le applet che contengono un riferimento al metodo getInetAddress() della classe Socket del package java.net.

Si noti che il primo e il secondo criterio sono in contraddizione: il primo dice di fermare le applet che contengono un riferimento alla classe Socket, il secondo permette di far passare le applet che contengono un riferimento ad un particolare metodo della classe Socket. In parole povere, un'applet contenente un'invocazione a Socket.getInetAddress() dovrebbe essere fermata dal primo criterio e fatta passare dal secondo. Come si risolve questo conflitto? La risposta e': i criteri piu' specializzati prevalgono su quelli piu' generali. In questo caso, il secondo criterio e' piu' specializzato del primo (in quanto fa riferimento ad un particolare metodo della classe), per cui e' quello che prevale.

In effetti il vero scopo dei criteri di tipo ALLOW e' quello di rendere meno restrittive alcune regole. Ad esempio, permettono di esprimere criteri del tipo "ferma tutte le applet che contengono un riferimento ad un certo package P, tranne quelle che usano le classi C1 e C2 di tale package". In mancanza di criteri di tipo ALLOW l'alternativa sarebbe di elencare tutte le classi del package P tranne C1 e C2. Usando criteri di tipo ALLOW, invece, alcune regole possono essere espresse in maniera piu' compatta. Si noti che una regola andrebbe resa meno restrittiva possibile per evitare di fermare anche applet che non hanno codice fraudolento. Ad esempio, se viene reso pubblico un bug che puo' essere sfruttato solo chiamando il metodo M della classe C del package P, allora conviene mettere un'opportuna regola di STOP solo su quel metodo, e non su tutta la classe o, peggio, su tutto il package. Per questo motivo il filtro che abbiamo realizzato permette di esprimere riferimenti con un'elevata granularita': oltre ai riferimenti ai metodi, infatti, e' possibile indicare riferimenti a variabili membro e addirittura a metodi con una particolare signature in caso di overloading del nome di un metodo.

Un altro tipo di criterio permette di bloccare tutte le applet che contengono una particolare sequenza di byte, espressi con il loro valore esadecimale. Un esempio di criterio di questo tipo e':

        MATCHBYTES cafebabe

Il criterio nell'esempio blocchera' qualsiasi applet poiche', come molti sapranno, questa sequenza di codici esadecimali e' presente all'inizio di ogni applet. Un criterio equivalente e' MATCHBYTECODE: la differenza con quello appena visto e' che soltanto la sequenza delle istruzioni bytecode viene presa in considerazione (e non tutto il resto dell'applet, che contiene anche altre informazioni). I criteri MATCHBYTES e MATCHBYTECODE ricordano le tecniche utilizzate dai software anti-virus, i quali individuano molti virus cercando una loro "traccia" nel filesystem. Vanno usati con cautela, perche' al contrario degli altri, richiedono una scansione completa dell'applet, e quindi sono meno efficienti.

Un altro criterio, infine, e' NOSUBCLASS: questo criterio permette di bloccare ogni tentativo di creare una sottoclasse di una classe specificata.

Come detto in precedenza, un file di configurazione puo' contenere un insieme di regole. In mancanza di regole, tutte le applet vengono fatte passare. Se un'applet soddisfa una delle regole, l'applet viene fermata (quindi, e' una condizione in OR). Perche' un'applet soddisfi una regola e' necessario che l'applet soddisfi tutti i criteri eccetto ALLOW, che ha il solo scopo di semplificare la scrittura delle regole (i criteri, quindi, sono una condizione in AND).

Utilizzo del Filtro
Il filtro descritto e' stato implementato in C, per ragioni di efficienza, e puo' essere aggiunto sia alla macchina virtuale Java del browser sia come plug-in per un firewall che sia in grado di intercettare le applet Java che arrivano dall'esterno.

Nel prototipo da noi realizzato abbiamo utilizzato la macchina virtuale del browser Netscape Navigator per provare l'efficacia del nostro filtro. Dal momento che ora e' possibile usare la macchina virtuale Sun sia con Netscape Navigator che con Microsoft Internet Explorer, aggiungendo il filtro a questa macchina virtuale e' possibile renderlo disponibile alla maggioranza degli utenti. Quando un utente carica una pagina contenente un'applet che viola una delle regole, allora l'applet non viene caricata e sulla console viene mostrato il messaggio causato dall'eccezione (RuleViolation) insieme con il nome della regola, in modo che sia possibile capire come mai un'applet non viene caricata. Nella prossima versione del nostro filtro al browser verra' passata un'applet "sostitutiva" al posto di quella bloccata. L'applet sostitutiva potrebbe visualizzare il messaggio di violazione della regola direttamente all'interno della pagina Web, e potrebbe anche essere modificata per particolari scopi. Ad esempio, oltre a visualizzare il messaggio potrebbe anche comunicare la violazione al responsabile della sicurezza della rete, in modo che possa prendere eventuali provvedimenti.

La modifica della macchina virtuale viene fatta modificando il ClassLoader. L'implementazione del ClassLoader dipende dal particolare browser, ma l'inserimento del filtro e' sempre banale. Esiste sempre un punto del codice, infatti, in cui e' disponibile il bytecode dell'applet (in genere rappresentato come array di tipo byte) dal quale si crea la corrispondente applet (intesa come oggetto Java). Per filtrare le applet e' sufficiente inserire una chiamata ad un metodo nativo immediatamente prima della creazione dell'applet, passando a questo metodo un riferimento al bytecode. Il filtro, a questo punto, analizza il bytecode rispetto alle regole fornite e solleva un'eccezione nel caso l'applet venga fermata da una o piu' regole.

Aggiungere il filtro alla macchina virtuale del browser richiede di aggiornare il browser. Una soluzione alternativa per proteggere un certo numero di utenti in maniera "trasparente" potrebbe essere quella di inserire il filtro in un firewall. Tecnicamente questo e' possibile senza modificare il firewall, in quanto alcuni prodotti di questo tipo permettono di realizzare plug-in che filtrano il traffico. In questo caso e' sufficiente che il firewall invii ogni applet proveniente dall'esterno al filtro, il quale comunicherebbe al firewall se far passare o meno l'applet. Attualmente questo tipo di soluzione e' ancora in fase di studio e non sono ancora disponibili dati su quanto un simile filtro inciderebbe sulle prestazioni del firewall.

Per quanto riguarda le regole, e' ragionevole aspettarsi di avere una regola corrispondente ad ogni bug ancora presente nella versione della macchina virtuale utilizzata (dandole, ad esempio, il nome del relativo bug). Quando il browser viene aggiornato e' opportuno eliminare le regole relative ai bug risolti, per evitare inutili rallentamenti. Essendo le regole molto semplici, e' molto semplice diffonderle. Ad esempio, quando un nuovo bug venisse scoperto la segnalazione ufficiale potrebbe anche indicare la regola da aggiungere al filtro per bloccare il bug. Un sito che elencasse tutti i security alert per bug nelle macchine virtuali Java potrebbe riportare anche le regole da utilizzare. Si potrebbe anche pensare ad un semplice protocollo per aggiungere/rimuovere regole in automatico, senza che l'utente debba preoccuparsene. In questo caso un amministratore di una rete aziendale potrebbe aggiornare remotamente le regole dei filtri degli utenti della propria rete, magari in base alla versione della macchina virtuale che essi usano.

Limiti dell'Approccio e Sviluppi Futuri
Pur fornendo un valido contributo, la soluzione presentata in questo articolo non e' sicuramente la soluzione definitiva al problema degli attacchi tramite applet Java. In questa sezione vengono discussi alcuni problemi relativi all'utilizzo di questo tipo di soluzione.

Il primo problema e' che il filtro e' efficace soltanto se e' possibile definire una regola non troppo restrittiva che individui un potenziale attacco. Se un attacco puo' essere effettuato sfruttando dei metodi comunemente utilizzati anche dalle applet "buone", definire una regola che blocchi quei metodi costituirebbe una forte restrizione all'utilizzo di Java. In metodi piu' frequentemente utilizzati, d'altra parte, sono anche quelli piu' "collaudati" e quindi, si spera, con meno bug. Dal momento che per una regola vengono forniti una serie di criteri valutati "in AND", si hanno piu' possibilita' di definire con precisione i criteri per bloccare un possibile attacco senza fermare applet innocue. Inoltre, e' sempre aperta la possibilita' di aggiungere nuovi tipi di criteri al filtro in modo da permettergli una maggiore accuratezza nell'individuazione di applet pericolose.

Un altro problema e' quello della definizione delle regole. Pur essendo basate su una sintassi molto semplice, e' un'operazione che richiede una certa competenza e che quindi non puo' essere effettuata dall'utente finale. Come accennato in precedenza, un'autorita' centrale potrebbe essere preposta alla definizione delle regole, che potrebbe ad esempio inviare ad esempio le regole, opportunamente firmate, agli utenti che ne facciano richiesta, oppure, nel caso di un'azienda, si potrebbe pensare ad un aggiornamento automatico completamente trasparente all'utente.

Per quanto riguarda l'efficienza, bisogna dire che il filtro non costituisce un grosso problema sotto questo punto di vista, specialmente se confrontato con il costo necessario al caricamento e all'esecuzione dell'applet nella macchina virtuale. L'algoritmo implementato per la verifica dei criteri di tipo STOP/ALLOW costruisce delle strutture dati ad hoc durante il caricamento dell'applet che gli permettono di effettuare la verifica di un criterio con una discesa in un'albero di 4 livelli. Per i criteri di tipo MATCHBYTES e MATCHBYTECODE l'algoritmo implementato e' quello "classico" di ricerca di una stringa in una sequenza di byte. Utilizzando algoritmi piu' sofisticati sarebbe possibile ottenere migliori prestazioni anche con questo tipo di criteri. I criteri di tipo NOSUBCLASS, infine, richiedono un tempo di verifica trascurabile.

Rimane da discutere la questione della possibilita' per un attaccante di eludere l'azione del filtro. Si noti, innanzitutto, che il filtro effettua un'analisi statica dell'applet prima che qualsiasi parte di essa sia stata eseguita. Non e' assolutamente possibile per un hacker introdurre del codice nell'applet che influenzi il comportamento del filtro. Sia nel caso del filtro all'interno della macchina virtuale Java, sia nel caso del filtro all'interno di un firewall, l'analisi viene effettuata prima che qualsiasi parte dell'applet sia stata caricata nell'ambiente di esecuzione. Per le restrizioni imposte dal linguaggio Java non e' possibile per un'applet "camuffarsi", ad esempio nascondendo le chiamate ai metodi che poi effettuera'. Il filtro, inoltre, e' concettualmente abbastanza semplice ed e' quindi ragionevole aspettarsi che sia possibile produrne una versione virtualmente priva di bug, che potrebbero essere sfruttati da un attaccante.

Come sviluppi futuri stiamo attualmente valutando la possibilita' di introdurre criteri di analisi statica del bytecode piu' sofisticate di quelle attuali, utilizzando tecniche di intelligenza artificiale. I criteri di questo tipo, essendo computazionalmente molto piu' costosi di quelli attuali, verrebbero applicati solo sulle applet che soddisfano i criteri attuali. In poche parole, con i criteri attuali si individuerebbero le applet "sospette" in maniera efficiente, le quali sarebbero poi analizzate a fondo con criteri piu' sofisticati per cercare di capire se le applet vanno realmente fermate.

Conclusioni
La soluzione presentata in quest'articolo costituisce un sostanziale passo avanti verso la protezione degli utenti nel caso di bug nella macchina virtuale Java. Allo stato attuale, infatti, le uniche alternative quando viene scoperto un bug nella macchina virtuale sono la disabilitazione della stessa, e i conseguenti problemi per l'accesso a siti che offrono servizi basati su Java, o correre il rischio di capitare in qualche sito con un'applet che utilizza il bug per prendere il controllo del sistema.
Utilizzando il filtro basato su regole, invece, e' possibile ridurre enormemente questi rischi, anche semplicemente fermando le applet che contengono metodi di accesso al filesystem, i quali in condizioni "normali" dovrebbero essere comunque bloccati a tempo d'esecuzione dalla macchina virtuale Java.

Note
Si ringrazia il dott. Fausto Fraticelli e il dott. Luigi Giuri per il valido contributo apportato al progetto descritto in quest'articolo.

Un articolo piu' approfondito sull'argomento sara' pubblicato negli atti della IEEE 14th Annual Computer Security Applications Conference (Dicembre 1998), di futura pubblicazione. Per altre informazioni e' possibile contattare l'autore all'indirizzo di posta elettronica iglio@fub.it.

I nomi delle societa' e dei prodotti riportati in questo articolo sono marchi registrati dai legittimi proprietari.


Pietro Iglio e' ricercatore alla Fondazione Ugo Bordoni di Roma dal 1995, dove si occupa di sicurezza informatica. Le sue aree di competenza includono: sicurezza di Java, modelli avanzati per il controllo degli accessi e la sicurezza delle basi di dati. Ha inoltre maturato significative esperienze nei campi della computer algebra, tecnologia dei compilatori, modelli ad oggetti e sistemi operativi.
 



 
 
 
 
 
MokaByte Web - 1998
www.mokabyte.it

MokaByte ricerca nuovi collaboratori. Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@infomedia.it