MokaByte
Numero 17 - Marzo 1998
|
|||
|
|
||
Fausto Fraticelli |
|
||
Il JDK 1.2 presenta un nuovo modello di sicurezza che rimane compatibile con le precedenti versioni, ma ne estende notevolmente le potenzialita'. I vantaggi piu' evidenti che ne derivano sono: amministrazione semplificata dei privilegi delle applet; configurazione dei privilegi anche per le applicazioni stand-alone; possibilita' di rilasciare i privilegi anche ai codici non firmati; creazione dei nuovi privilegi in maniera semplice e trasparente.
Introduzione
Sandbox
La struttura
classica della sicurezza di Java punta principalmente a prevenire attacchi
da parte di applet caricate dalla rete nel sistema locale (vedi figura
2). Il modello e' il sandbox . Con tale termine vengono incluse una serie
di strumenti che agiscono in fase di caricamento (bytecode verifier) e
d’esecuzione (security manager), che hanno il compito di controllare che
il codice dell’applet caricata rispetti le regole semantiche del linguaggio
Java ed evitare che l’applet usi indiscriminatamente le risorse critiche
del sistema locale. Alcune delle operazioni potenzialmente pericolose e
necessariamente da proteggere sono: lettura/scrittura su file system, connessioni
ad host diversi da quello da cui provengono, utilizzare procedure native,
eseguire comandi della classe java.lang.Runtime come l’exec e l’exit, etc..
JDK 1.1.x
Il secondo passo
nelle versioni successive del JDK (dalla 1.1) e’ stato quello di aumentare
i privilegi delle applet esterne considerate "fidate". Per tale scopo sono
stati inseriti nuovi packages riguardanti strumenti di crittografia, digesting,
firme digitali (digital signing), certificazione e liste di controllo degli
accessi (ACL) alle risorse.
Inoltre sono
stati introdotti alcuni tools (javakey, jar) per gestire databases locali
contenenti entità autenticabili e relative chiavi e per creare
i JAR files contenenti le applet firmate.
Anche se sono
stati compiuti notevoli passi in avanti, rimane comunque complessa la gestione
dei privilegi d'accesso e la configurazione di una security policy. Inoltre
i tools possono essere utilizzati per aumentare i privilegi solo a quelle
applet che vengono autenticate in base alla firma che le accompagna.
Sicurezza nel JDK 1.2
Il modello di
sicurezza del JDK 1.2 presenta aspetti del tutto nuovi che fanno riferimento
ai seguenti concetti e strumenti:
. domini;
. security policy;
. permessi;
. AccessController.
Domini
La versione
1.2 del JDK (release beta 2) introduce una nuova struttura nel modello
di sicurezza basato sul concetto dei domini di protezione. Un dominio di
protezione e' un insieme di privilegi (o permessi) associati ad un insieme
di codici Java (applet o applicazioni) aventi le seguenti caratteristiche
comuni:
- provenienza
da uno specifico CODEBASE (es: "http://www.serv_host.com/", "*", "file:///C|/.../index.html");
- firmate usando
tutte le firme digitali appartenenti ad uno specifico insieme di firme.
Quindi un dominio
di protezione (o dominio) puo' esser visto intuitivamente come un insieme
di applet e/o applicazioni Java raggruppate in base alla loro provenienza
(di tipo java.net.URL) e alle chiavi pubbliche (rappresentata da oggetti
di tipo java.security.PublicKey) utilizzate per verificare le loro firme.
Il risultato e' che il codice Java viene caratterizzato dalla sua origine
(URL) e dall'insieme di chiavi che lo accompagna. Nel resto di questo articolo
quando diremo che un codice Java appartiene ad un dominio si vuole intendere
che quel codice possiede le proprieta' (URL, chiavi) associate a quel dominio.
Domini speciali
sono:
- il dominio
di sistema, si riferisce a tutto il codice Java incluso nel CLASSPATH
del sistema locale.
- il sandbox,
al quale appartengono i codici Java che non hanno privilegi speciali nell'host
locale;
Nella coppia
(URL, chiavi) che caratterizza il dominio di sistema, la URL corrisponde
al CLASSPATH di sistema e l'insieme di chiavi pubbliche e' vuoto,
ossia il codice derivante dal CLASSPATH non necessita di essere autenticato.
La coppia (URL,
chiavi) che si riferisce al sandbox (dominio che potrebbe anche non esistere
qualora si rilasciassero dei privilegi a tutta l'utenza di Internet), include
tutte le coppie (URL, chiavi) non privilegiate nel dominio di sistema (nel
seguito analizzeremo meglio questi concetti).
Ogni codice
Java (applet o applicazione) e' associato ad uno specifico dominio a seconda
della sua provenienza e delle firme che porta con se'; inoltre, per poter
accedere alle risorse protette dal dominio di sistema (gestione di rete,
file system, etc..) deve avere permessi specifici di questo dominio. Nel
caso in cui un’applicazione non avesse il permesso di utilizzare risorse
associate ad un dominio, viene rilevata una SecurityException.
Il fatto che
il dominio si basi sulla coppia (URL, chiavi) permette di definire una
specifica politica di sicurezza anche per le applicazioni stand-alone.
Infatti una URL puo' essere di tipo file:///C|/.../index.html e la firma
digitale e' indipendente dalla provenienza del codice.
Quindi ogni
dominio puo' avere delle risorse da proteggere attraverso degli accessi
controllati e puo' avere lui stesso dei permessi su altri domini. Nell'ambito
di questo articolo ci interessiamo solo di come il dominio di sistema protegge
l'accesso alle risorse di sistema e di come l'utente possa configurare
una propria politica di sicurezza. Nella figura 1 e' mostrato un'esempio
di come si possono gestire i permessi del dominio di sistema a seconda
dei domini di appartenenza dei codici.
Figura 2
In questo esempio il dominio di sistema rilascia il permesso di eseguire il metodo exec e di connettersi a host diversi da quello di origine al dominio D0; al dominio D1 da' i privilegi di lettura/scrittura sulla directory /public. Nel seguito vedremo come fa a rilasciare i permessi del dominio di sistema ai domini non di sistema (application domain), ossia ai vari codici non interni al CLASSPATH.
Policy e Permission
E' possibile
definire i permessi sugli oggetti del dominio di sistema e conservarli
in un'oggetto chiamato Policy. Una policy e’ semplicemente una lista di
permessi rilasciati ai codici a seconda della loro provenienza o delle
loro firme. Il fine e’ permettere ad un utente di incrementare o negare
i permessi di sistema, in maniera semplice, ad un’entità locale
o remota (URL, utenti firmati, tutti gli utenti di Internet, etc..).
Vediamo un esempio
di policy:
grant {Un blocco grant rilascia dei permessi specifici ai codici che provengano dalle URL (opzionali) e dai firmatari (opzionali) che seguono il grant. Il primo blocco dell'esempio rilascia un permesso a tutti gli utenti di Internet, il secondo rilascia un permesso ai codici firmati da Tizio e Caio ed il terzo si riferisce ai codici provenienti da http://myhost.it e firmati da Tizio. Il blocco seguente:
permission java.io.FilePermission "/tmp/readme.txt", "read";
};
grant signedBy "Tizio,Caio" {
permission java.io.FilePermission "/tmp", "read";
};
grant CodeBase "http://myhost.it/", signedBy "Tizio" {
permission java.io.FilePermission "/tmp", "read";
permission java.net.SocketPermission "*", "connect";
};
grant CodeBase "http://myhost.it/", signedBy "Tizio" {non fa altro che caricare nel Policy un permesso. Questo permesso si riferisce alla possibilita' da parte dei codici provenienti da http://myhost.it/ e firmati da Tizio di leggere il file readme.txt della directory /tmp.
permission java.io.FilePermission "/tmp/readme.txt","read";
}
Ad esempio tramite
il SocketPermission si possono rilasciare permessi a codici interni e/o
esterni per connettersi ad altri host; con il RuntimePermission si puo'
dare il permesso di eseguire un exec o un exit, etc..
La Policy (contenente
l'insieme di permessi rilasciati ai codici autorizzati) viene caricata
nel momento in cui si inizializza la macchina virtuale di Java (JVM). Nel
caso in cui la Policy sia vuota, allora e' come se si applicasse il modello
sandbox per tutti i codici esterni al CLASSPATH. La Policy puo' essere
configurata e/o modificata anche dinamicamente, ossia dopo che sia stata
gia' inizializzata. Puo' essere istanziata una sola Policy nella JVM, ossia
non possono essere caricate contemporaneamente due Policy.
AccessController
Supponiamo che
un'applicazione faccia una chiamata ad un metodo protetto (M) del dominio
di sistema. Il metodo prima di svolgere il proprio compito chiama (direttamente
o indirettamente) l'oggetto AccessController per verificare che l'applicazione
(appartenente ad un determinato dominio) abbia il permesso di invocare
il metodo. L'AccessController reperisce le informazioni sui permessi che
il dominio dell'applicazione possiede sul dominio di sistema. Se tra questi
permessi e' presente quello di utilizzare il metodo M, l'AccessController
non fa altro che ritornare al metodo, che eseguira' normalmente l'operazione.
In caso contrario l'AccessController riportera' una SecurityException (anzi,
una java.security.AccessControlException) e l'operazione non verra' eseguita.
Quindi l'oggetto
AccessController si occupa di verificare che l'applicazione abbia i giusti
permessi sul metodo chiamato, similmente a quanto faceva il SecurityManager
con i check. Pero' l'AccessController non esegue un semplice check.
Innanzitutto
verifica a quale contesto appartiene l'applicazione. Poi si fa dare dall'oggetto
Policy la lista di permessi rilasciati a quel contesto. Infine verifica
che in questa lista di permessi ci sia quello di utilizzare il metodo M.
Configurazione di una propria Security Policy
In questa sezione
descriviamo come si puo' configurare una propria politica di sicurezza.
Cio' ci permettera' di approfondire anche i meccanismi di verifica ed autenticazione
dei codici firmati. In questo esempio ci mettiamo prima dalla parte del
creatore (chiamiamolo Fido) e firmatario di una applet che voglia eseguire
operazioni privilegiate in un normale client host. In seguito vedremo come
un client (chiamiamolo Diffido) debba settare la sua policy per autenticare
i codici appartenenti a Fido e per dare loro i privilegi necessari.
Creazione chiavi
Innanzitutto
Fido deve avere una coppia di chiavi (pubblica e privata). Con la chiave
privata firma i file da mandare. Diffido deve avere una copia della chiave
pubblica di Fido per poter verificare la firma di Fido. Per creare una
coppia di chiavi Fido eseguira’ il seguente comando:
keytool -genkey -alias Fido -keypass fido@16.1.98/10,30hcon il quale crea un alias (Fido) e inserisce una password (fido@16.1.98/10,30h) per usare la propria chiave privata. Il comando keytool memorizzerà le chiavi e gli eventuali certificati in un oggetto chiamato keystore (implementazione della Sun della classe astratta java.security.KeyStore), memorizzandolo in un file e proteggendolo adeguatamente con una password. Dopo la richiesta della password usata per proteggere il keystore creato (nell’esempio ho usato fidonew) e l’inserimento di alcune informazioni personali (nome e cognome, società, città, etc..) verranno create le chiavi da usare per firmare i propri codici e farli autenticare. Il keystore verra’ salvato come file .keystore nella home directory dell’utente (supponiamo in /).
Firma dell'applet
A questo punto
Fido dovra’ creare un file .jar (chiamiamolo FidoSignedApplet.jar) contenente
i file .class dell’applet (supponiamo che l’applet sia un unico file: FidoApplet.class).
Per creare questo file basta eseguire la seguente linea di comando:
jar cf FidoSignedApplet.jar FidoApplet.classOra bisogna che Fido firmi la sua applet (contenuta nel .jar file) con la linea di comando:
jarsigner -keystore /.keystore -storepass fidonew -keypass fido@16.1.98/10,30h FidoSignedApplet.jar FidoQuesta istruzione genera il file FidoSignedApplet.jar derivante dall’aggiunta dei file fido.sf e fido.dsa al precedente FidoSignedApplet.jar. Si noti l’uso delle password (-storepass fidonew .. -keypass fido@16.1.98/10,30h) per accedere al keystore di Fido e alla chiave privata memorizzata all’interno del keystore. Come risultato FidoSignedApplet.jar conterra' oltre a FidoApplet.class i file manifest.mf, fido.sf e fido.dsa che servono a Diffido per autenticare Fido e per verificare l'integrita' dell'applet caricata.
Tag archive
Ora basta che
Fido prepari una pagina HTML (FidoApplet.html) con il tag seguente:
<applet code=FidoApplet.class archive="FidoSignedApplet.jar" width=100 height=100> </applet>Download della chiave pubblica
keytool -export -alias Fido -file Fido.certUna volta ottenuto il file Fido.cert Diffido lo importa nel suo database associandolo ad un alias per Fido (NickFido) con l’istruzione seguente:
keytool -import -alias NickFido -file Fido.certQuesto comando crea un nuovo record nel file .keystore (di Diffido) con alias NickFido, in cui si memorizza la chiave pubblica di Fido (necessaria per verificare la sua firma) e si indica se questa e’ stata certificata. E’ l’utente locale stesso che dovra’ indicare se la chiave può essere considerata sufficientemente certificata. Finora abbiamo creato le basi per permettere a Diffido di autenticare i codici di Fido.
Gestione del Policy
Ora vediamo
come sia possibile gestire i permessi su questi codici. Volendo rilasciare
piu' privilegi nelle operazioni sul file system, Diffido potrebbe aggiungere
il seguente grant nel file di configurazione personale (ad es. DiffidoPolicy.txt):
grant signedBy "NickFido" {Questo grant rilascia i privilegi d'accesso in lettura su tutto il file system di Diffido e in scrittura sulla directory /home_Diffido ai codici firmati da Fido (che nel sistema di Diffido ha l'alias "NickFido") senza preoccuparsi della loro provenienza.
permission java.io.FilePermission "*", "read";
permission java.io.FilePermission "/home_Diffido/*", "read,write";
};
Appletviewer
Per impostare
il proprio file policy quando si usa l’appletviewer basta associare -Djava.policy
al nome del file. Ad esempio caricando l’applet di Fido dal suo sito con
il comando seguente:
appletviewer -J-Djava.policy=/home_Diffido/DiffidoPolicy.txt http://www.fidohost.it/FidoApplet.html
si abilita l’applet
a scrivere nella directory /home_Diffido e a leggere tutti i file del file
system locale. Infine e' previsto l'utilizzo dell'opzione -Djava.policy
per settare una propria policy anche per le applicazioni stand-alone.
Conclusioni
In questo articolo
si e' visto come il modello di sicurezza del JDK 1.2 permetta di gestire
in maniera semplice le liste di accesso alle risorse locali, di applicarle
alle applicazioni stand-alone e di svincolarle dall’autenticazione tramite
firme digitali.
L’analisi fatta
non puo’ essere esauriente finche’ non si verificano i cambiamenti apportati
alla JVM del JDK su un Java-enhanced browser. L’appletviewer del JDK 1.2
per quanto sia utilizzabile per testare il nuovo modello, non può
essere considerato un banco di prova affidabile, infatti molte delle operazioni
normalmente protette dal sandbox nei normali Java-enhanced browser non
sono protette dall'appletviewer.
|
||
|
||
MokaByte ricerca
nuovi collaboratori
|
||
|