Il modello di sicurezza esteso di Java

Università degli Studi di Roma “La Sapienza”
Dipartimento di Informatica e Sistemistica
Il modello di sicurezza esteso di Java
Crittografia e Sicurezza, a.a. 2004/2005
Emiliano Trevisani
Contatti
‰
‰
Emiliano Trevisani:
ƒ
Via Salaria 113, Stanza C2
ƒ
[email protected]
Lucidi e links utili su http://www.dis.uniroma1.it/~trevisani
Summary
‰
Overview
‰
Norma di sicurezza configurabile;
‰
Permessi della norma di sicurezza: la classe Permission e security policies;
‰
Esempio di norma di sicurezza;
‰
Estensione della sandbox;
‰
Sicurezza delle applicazioni;
‰
Supporto per la crittografia: Java Cryptography Extension [JCE]
Overview
‰
‰
‰
Modello di sicurezza [JDK 1.2]:
1.2]
ƒ
Integrato nell’ambiente di esecuzione: il codice è vincolato a rispettare una norma di sicurezza in base al
principio del minimo privilegio;
ƒ
Approccio a 2 livelli: sicurezza delle applicazioni e delle applet;
ƒ
Potente e flessibile: supporta controlli d’accesso a rilevazione fine;
ƒ
Supporto per la crittografia: Java Cryptography Extension [JCE] e API Security JDK 1.2;
Sicurezza delle applet:
applet
ƒ
La sandbox consente di eseguire in modo sicuro il codice potenzialmente pericoloso prelevato dalla rete:
ƒ
Meccanismi per rilassare i vincoli di sicurezza applicati al codice: norma di sicurezza configurabile;
ƒ
Soluzione molto più flessibile rispetto ai modelli di sicurezza di tipo ON/OFF [es. JDK1.1 - controlli
ActiveX];
Sicurezza delle applicazioni:
applicazioni
ƒ
Per default, tutte le classi caricate dal CLASSPATH vengono trattate come classi di sistema, considerate
sicure e pertanto non sottoposte alla norma di sicurezza;
ƒ
A partire dal JDK 1.2 è possibile forzare l’esecuzione di un’applicazione all’interno della norma di sicurezza
corrente [SecureClassLoader]
Norma di sicurezza configurabile
Generalità
‰
Principio del minimo privilegio: il codice in esecuzione deve possedere privilegi d’accesso alle risorse appena
sufficienti a completare le sue funzioni.
‰
Approccio alla sicurezza del JDK 1.0:
1.0
‰
‰
ƒ
applet non possono accedere, in nessuna caso, a risorse di rete o di sistema; applicazioni sicure per default;
ƒ
meccanismo efficace ma limitativo;
Approccio alla sicurezza del JDK 1.1:
1.1
ƒ
poco flessibile [ON/OFF];
ƒ
principio del minimo privilegio non soddisfatto;
ƒ
Esempio: SecureApplet
Approccio alla sicurezza del JDK 1.2:
1.2
ƒ
Architettura che consente l’implementazione del principio del minimo privilegio;
ƒ
L’idea base è la definizione di una norma di sicurezza che conceda ad applicazioni ed applet diversi gradi di
accesso alle risorse;
ƒ
Il livello di dettaglio dei permessi d’accesso è tale da consentire la configurazione di una norma allo stesso
tempo potente e flessibile;
Norma di sicurezza configurabile
Approccio alla sicurezza del JDK 1.0
Ambiente senza restrizioni
Applicazioni [sicure]
Applet non firmate
[non sicure]
Risorse di rete e di sistema
SANDBOX
Norma di sicurezza configurabile
Approccio alla sicurezza del JDK 1.1
Ambiente senza restrizioni
Applicazioni [sicure]
Applet non firmate
[non sicure]
SANDBOX
Applet firmate
[sicure]
Risorse di rete e di sistema
Norma di sicurezza configurabile
Approccio alla sicurezza del JDK 1.2
- Modello di sicurezza configurabile -
Applet
Applicazioni
Dominio 4
Dominio 2
Dominio 6
Dominio 3
Dominio 5
Dominio 1
Risorse di rete e di sistema
Norma di sicurezza configurabile
Specifica di una norma di sicurezza 1/2
‰
La norma di sicurezza da implementare viene descritta attraverso un opportuno file di testo;
‰
Il file della norma di sicurezza è costituito da una serie di voci di assegnazione che identificano i permessi
assegnati al codice in base alla sua provenienza ed all’identità dei suoi firmatari.
‰
Ad ogni voce di assegnazione possono corrispondere più voci di permesso;
‰
JRE associa a qualunque codice in esecuzione, l’URL dalla quale il codice stesso è stato caricato e lista dei suoi
firmatari [eventualmente vuota];
ƒ
I firmatari sono identificati attraverso i rispettivi alias, associati alle corrispondenti chiavi pubbliche;
ƒ
Gli alias e le chiavi pubbliche sono archiviate nella keystore dell’utente;
‰
L’interprete di bytecode JAVA carica la norma di sicurezza da adottare all’atto dell’esecuzione;
‰
La norma di sicurezza può essere caricata da sorgenti diverse:
1.
Creando o modificando la norma
<java_home>\lib\security\java.policy;
di
default
del
sistema,
in
generale
contenuta
nel
file
2.
Sostituendo il valore della proprietà di sistema java.policy con il nome di un altro file contente la nuova
norma di sicurezza;
Permessi della norma di sicurezza
Specifica di una norma di sicurezza 2/2
3.
Creando o modificando il file contenente la norma di default per l’utente, in generale contenuta nel file
<user_home>\java.policy;
4.
Sostituendo il valore della proprietà java.security.policy con il nome di un diverso file per la norma di
sicurezza; si utilizza l’opzione –D da riga di comando:
Esempio: java –Djava.security.policy==“
Djava.security.policy==“new.policy”
new.policy” prova
Esegue la classe prova utilizzando la norma contenuta del file new.policy; questa sostituirà la norma di default
per quest’esecuzione; l’uso di un solo segno d’uguaglianza aggiunge la norma a quella di default.
5.
Sostituendo la classe java.security.PolicyFile che implementa la norma di sicurezza con un’altra classe
modificando il file java.security in <java_home>\lib\security\java.security; occorre sostituire la riga
policy.provider=java.security.PolicyFile con policy.provider=OtherClass.
Permessi della norma di sicurezza
Sintassi delle voci di assegnazione
‰
Le voci di assegnazione iniziano con la parola chiave grant seguita dalle clausole SignedBy e CodeBase:
ƒ
grant [SignedBy “firmatario_1,firmatario_2,…”] [, CodeBase “URL”]
{ voci di permesso
};
‰
La clausola SignedBy contiene la lista degli alias dei firmatari separati da virgole; se il codice non è stato firmato o
si desidera che la norma non tenga conto di eventuali firmatari, la clausola SignedBy può essere omessa;
ƒ
‰
‰
Esempio: SignedBy “Bob, Alice”;
La clausola CodeBase si riferisce a tutto il codice caricato dalla URL specificata e da tutti i suoi sottopercorsi:
ƒ
Esempio: Codebase “http://www.dis.uniroma1.it”
ƒ
Esempio: Codebase “http://www.dis.uniroma1.it/didattica/”: tutto il codice caricato dalla cartella didattica e
da tutte le sue sottodirectory di www.dis.uniroma1.it
ƒ
Esempio: Codebase “file://local/applets/”: tutto il codice caricato dalla cartella local e da tutte le sue
sottodirectory del file system locale.
Se la clausola CodeBase è omessa la voce si riferisce a tutte le fonti di codice
Permessi della norma di sicurezza
Voci di permesso 1/4
‰
Una voce di permesso consiste con la parola chiave permission, seguita dal nome completo di una classe di
permessi Java, dal nome opzionale di una destinazione, da un elenco di azioni e dalla clausole SignedBy:
ƒ
permission nome_classe_permesso [“target”] [,”action list”] [, SignedBy ”firmatari”];
‰
Il nome della classe dei permessi identifica il tipo di permesso da assegnare: si tratta del nome completo della classe
Java che implementa il permesso in questione;
‰
La gerarchia della classe Permission è la seguente:
java.security.Permission
java.security.BasicPermission
java.security.AWTPermission
java.io.SerializalePermission
java.lang.reflect.ReflectPermission
java.lang.RuntimePermission
java.net.NetPermission
java.security.SecurityPermission
java.util.PropertyPermission
java.io.FilePermission
java.net.SocketPermission
Permessi della norma di sicurezza
Voci di permesso 2/4
‰
La classe java.io.FilePermission è utilizzata per controllare l’accesso del codice al file system locale;
‰
La classe java.net.SocketPermission è utilizzata per determinare il modo con il quale il codice può accedere ai
socket TCP/UDP;
‰
La classe java.util.PropertyPermission è utilizzata per controllare l’accesso del codice alle proprietà Java;
‰
Il target identifica le risorse o i servizi che costituiscono l’oggetto dell’autorizzazione:
‰
‰
ƒ
Un file o una directory per java.io.FilePermission;
ƒ
Una proprietà per java.util.PropertyPermission;
Action list indica le azioni che il codice proveniente da una determinata origine è autorizzato a compiere:
ƒ
read, write, delete, execute sono le azioni correlate a java.io.FilePermission;
ƒ
accept, connect, listen, resolve sono le azioni correlate a java.net.SocketPermission;
La clausola ozpionale SignedBy indica che la voce di permesso è firmata e implica che la classe di permessi deve
essere firmata da tutti i firmatari in elenco.
Esempio di norma di sicurezza
Voci di permesso 3/4
grant CodeBase “http://www.dis.uniroma1.it/verified”
{ permission java.net.SocketPermission “www.uniroma2.it:1090”, “connect”;
}// a tutto il codice scaricato dal percorso http://www.dis.uniroma1.it/verified [e da tutti i possibili sottopercorsi]
// permesso di creare un socket TCP e connetterlo a www.uniroma2.it sulla porta 1090
grant CodeBase “http://www.dis.uniroma1.it/verified”, SignedBy “Alice,Bob”
{ permission java.io.FilePermission “-”, “read,write,delete,execute”;
permission java.net.PropertyPermission “*”, “read,write”;
permission java.lang.RuntimePermission “queueJob”;
} // a tutto il codice scaricato dal percorso http://www.dis.uniroma1.it/verified [e da tutti i possibili sottopercorsi]
// permesso di leggere, scrivere, eliminare, eseguire qualsiasi file del fyle system locale
// permesso di leggere e/o scrivere qualsiasi proprietà
// permesso di inviare una stampa nella coda di stampa locale;
Esempio di norma di sicurezza
Voci di permesso 4/4
grant CodeBase “file://c:/verified”
{ permission java.lang.RuntimePermission “createClassLoader”;
}// a tutto il codice scaricato dal percorso c:/verified del file system locale [e da tutti i possibili sottopercorsi]
// permesso di creare un proprio caricatore di classe
grant
{ permission java.util.PropertyPermission “java.version”, “read”;
}// a tutto il codice [qualsiasi provenienza, firmato o meno]
// permesso di leggere la proprietà java.version.
Esempio di norma di sicurezza
File di default java.policy 1/3
// Standard extensions get all permissions by default
grant codeBase "file:${java.home}/lib/ext/*" {
permission java.security.AllPermission;
};
// default permissions granted to all domains
grant {
// Allows any thread to stop itself using the java.lang.Thread.stop()
// method that takes no argument.
// Note that this permission is granted by default only to remain
// backwards compatible.
// It is strongly recommended that you either remove this permission
// from this policy file or further restrict it to code sources
// that you specify, because Thread.stop() is potentially unsafe.
// See "http://java.sun.com/notes" for more information.
Esempio di norma di sicurezza
File di default java.policy 2/3
permission java.lang.RuntimePermission "stopThread";
// allows anyone to listen on un-privileged ports
permission java.net.SocketPermission "localhost:1024-", "listen";
// "standard" properies that can be read by anyone
permission java.util.PropertyPermission "java.version", "read";
permission java.util.PropertyPermission "java.vendor", "read";
permission java.util.PropertyPermission "java.vendor.url", "read";
permission java.util.PropertyPermission "java.class.version", "read";
permission java.util.PropertyPermission "os.name", "read";
permission java.util.PropertyPermission "os.version", "read";
permission java.util.PropertyPermission "os.arch", "read";
permission java.util.PropertyPermission "file.separator", "read";
Esempio di norma di sicurezza
File di default java.policy 3/3
permission java.util.PropertyPermission "path.separator", "read";
permission java.util.PropertyPermission "line.separator", "read";
permission java.util.PropertyPermission "java.specification.version", "read";
permission java.util.PropertyPermission "java.specification.vendor", "read";
permission java.util.PropertyPermission "java.specification.name", "read";
permission java.util.PropertyPermission "java.vm.specification.version", "read";
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
permission java.util.PropertyPermission "java.vm.specification.name", "read";
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
};
Estensione della sandbox 1/4
SecureApplet code
import java.applet.*;
import java.awt.*;
public class SecureApplet extends Applet
{
private TextArea text;
private Panel panel;
public void init()
{
text=new TextArea();
panel=new Panel();
setLayout(new BorderLayout());
add("North",panel);
add("Center",text);
text.setText(System.getProperty("user.home"));
}
}
Estensione della sandbox 2/4
Access Control Exception
Estensione della sandbox
Modifica della norma di sicurezza: [file java.policy]
………………………..
………………………..
permission java.util.PropertyPermission "java.specification.version", "read";
permission java.util.PropertyPermission "java.specification.vendor", "read";
permission java.util.PropertyPermission "java.specification.name", "read";
permission java.util.PropertyPermission "java.vm.specification.version", "read";
permission java.util.PropertyPermission "java.vm.specification.vendor", "read";
permission java.util.PropertyPermission "java.vm.specification.name", "read";
permission java.util.PropertyPermission "java.vm.version", "read";
permission java.util.PropertyPermission "java.vm.vendor", "read";
permission java.util.PropertyPermission "java.vm.name", "read";
permission java.util.PropertyPermission “user.home",
";
user.home", "read
"read";
};
La successiva esecuzione
dell’applet non genera
AccessControlException
Estensione della sandbox 2/4
No Access Control Exception
Sicurezza delle applicazioni
‰
Anche le applicazioni possono essere vincolate a rispettare la norma di sicurezza corrente: occorre eseguirle tramite
SecureClassLoader;
‰
Normalmente le classi caticate dal CLASSPATH vengono caricate tramite un caricatore di classe nullo, ossia
considerate classi di sistema [sicure]e pertanto non sottoposte alla norma di sicurezza;
‰
A partire dal JDK1.2 è possibile caricare le classi locali da un secondo percorso di classe, specificato dalla proprietà
di sistema java.app.class.path:
‰
Questa proporietà può essere passata all’interprete di bytecode da linea di comando:
ƒ
java –Djava.app.class.path=“/untrusted” MyUnstrustedApplication
Carica l’applicazione utilizzando un SecureClassLoader e assicura che quest’ultima sia sottoposta alla norma di
sicurezza;
Supporto per la crittografia
JCE: Java Cryptography Extension 1/7
‰
Integrato in Java 2 SDK a partire dalla versione 4;
‰
Comprende un set di packages che forniscono un framework e l’implementazione per le seguenti funzionalità:
ƒ
Encryption / Decryption [symmetric, asymmetric, block and stream ciphering];
ƒ
Key generation and key agreement;
ƒ
Message Authentication Code [MAC] algorithms;
‰
Struttura flessibile: attraverso l’utilizzo di interfacce e provider è possibile utilizzare diverse implementazioni degli
stessi algoritmi [plug in] o addirittura algoritmi non contemplati nella definizione originale da SunJCE;
‰
Attualmente il SunJCE provider fornisce le implementazioni dei seguenti algoritmi:
ƒ
DES, AES, Diffie-Hellman key agreement among multiple parties, HmacMD5, HmacSHA, RSA…..
ƒ
Link utili:
¾
http://java.sun.com/products/jce/doc/guide/API_users_guide.html
¾
http://www.crionics.com/products/jpdf/tutorials/cp-basics.jsp
¾
http://www.rsasecurity.com
Supporto per la crittografia
JCE: Java Cryptography Extension 2/7
‰
API Specifications and more informations: http://java.sun.com/products/jce/index.jsp
‰
Esempi: cifratura DES e 3-DES di un testo: JCE_DES.java e JCE_3DES.java [codice on line]:
‰
Commenti al codice:
ƒ
Selezione del provider dei servizi di crittografia:
Security.addProvider(
Security.addProvider(new com.sun.crypto.provider.SunJCE());
com.sun.crypto.provider.SunJCE());
ƒ
Creazione di una chiave DES generata “casualmente” e scrittura su file della chiave:
Key key;
key;
KeyGenerator generator= KeyGenerator.getInstance(
KeyGenerator.getInstance("DES");
"DES");
generator.init(
generator.init(new SecureRandom());
SecureRandom());
key=generator.generateKey();
ObjectOutputStream out=new
out=new ObjectOutputStream(
ObjectOutputStream(new FileOutputStream(
FileOutputStream("des.key"
des.key"));
out.writeObject
out.writeObject((key);
key);
out.close
();
out.close();
Supporto per la crittografia
JCE: Java Cryptography Extension 3/7
ƒ
Istanza dell’algoritmo di cifratura [DES]:
Cipher cipher=Cipher.getInstance("DES/ECB/PKCS5Padding"
);
cipher=Cipher.getInstance("DES/ECB/PKCS5Padding");
ƒ
Inizializzazione dell’algotirmo di cifratura [ENCRYPT_MODE]
cipher.init(Cipher.ENCRYPT_MODE,
key);
);
cipher.init(Cipher.ENCRYPT_MODE,key
ƒ
Cifratura: [La variabile text contiene il testo in chiaro (una stringa)]
byte[]
);
byte[] stringBytes=text.getBytes("UTF8"
stringBytes=text.getBytes("UTF8");
byte[]
);
byte[] raw=cipher.doFinal(stringBytes
raw=cipher.doFinal(stringBytes);
BASE64Encoder encoder = new BASE64Encoder();
String base64 = encoder.encode(
encoder.encode(raw);
raw);
System.out.println(base64);
System.out.println(base64);
Algorithm / Mode / PaddingScheme
Supporto per la crittografia
JCE: Java Cryptography Extension 4/7
ƒ
Inizializzazione dell’algotirmo di decifratura [DECRYPT_MODE]
cipher.init(Cipher.DECRYPT_MODE,
key);
);
cipher.init(Cipher.DECRYPT_MODE,key
ƒ
Decifratura:
cipher.init(Cipher.DECRYPT_MODE,
key);
);
cipher.init(Cipher.DECRYPT_MODE,key
BASE64Decoder decoder = new BASE64Decoder();
byte[]
byte[] raw = decoder.decodeBuffer(
decoder.decodeBuffer(args[
args[1]);
byte[]
byte[] stringBytes = cipher.doFinal(
cipher.doFinal(raw);
raw);
String result = new String(
String(stringBytes,
stringBytes,"UTF8");
"UTF8");
System.out.println(
System.out.println(result);
result);
Supporto per la crittografia
JCE: Java Cryptography Extension 5/7
‰
Esempio: cifratura RSA [ECB] di un file: JCE_RSA.java
JCE_RSA.java [codice on line]:
‰
Commenti al codice:
ƒ
Implementazione RSA SunJCEProvider:
MAX_RSA_INPUT_LENGTH=117;
RSA_OUTPUT_LENGTH=128;
ƒ
Selezione del provider dei servizi di crittografia:
Security.addProvider(
Security.addProvider(new com.sun.crypto.provider.SunJCE());
com.sun.crypto.provider.SunJCE());
ƒ
Generazione di una coppia di chiavi [publica-privata] per RSA:
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kpg.initialize(1024); // RSA Key Generator Module Init
KeyPair kp = kpg.generateKeyPair();
kpg.generateKeyPair();
RSAPublicKey=kp.getPublic();
RSAPrivateKey=kp.getPrivate();
Supporto per la crittografia
JCE: Java Cryptography Extension 6/7
ƒ
Istanza dell’algoritmo di cifratura [RSA]:
Cipher RSACipher = Cipher.getInstance("RSA")
Cipher.getInstance("RSA")
ƒ
Inizializzazione dell’algotirmo di cifratura [ENCRYPT_MODE]
RSAcipher.init(Cipher.ENCRYPT_MODE,
RSAcipher.init(Cipher.ENCRYPT_MODE, RSAPublicKey);
RSAPublicKey);
ƒ
Cifratura: [La variabile data contiene i byte in chiaro (byte[])]
byte[] dataEncoded;
dataEncoded;
dataEncoded=RSACipher.doFinal(data);
ƒ
Inizializzazione dell’algotirmo di cifratura [DECRYPT_MODE]
RSAcipher.init(Cipher.DECRYPT_MODE,
RSAcipher.init(Cipher.DECRYPT_MODE, RSAPrivateKey);
RSAPrivateKey);
ƒ
Decifratura: [La variabile dataEncoded contiene i byte cifrati (byte[])]
byte[] dataDecoded;
dataDecoded;
dataDecoded=RSACipher.doFinal(dataEncoded
);
dataDecoded=RSACipher.doFinal(dataEncoded);
Esercizio: Implementare RSARSA-CBC
Supporto per la crittografia
JCE: Java Cryptography Extension 7/7
‰
Esempio: digest SHA-1 di un file: JCE_SHA1.java
JCE_SHA1.java [codice on line]:
‰
Commenti al codice:
ƒ
Selezione del provider dei servizi di crittografia:
Security.addProvider(
Security.addProvider(new com.sun.crypto.provider.SunJCE());
com.sun.crypto.provider.SunJCE());
ƒ
Istanza dell’algoritmo di hashing:
MessageDigest sha = MessageDigest.getInstance("SHA
MessageDigest.getInstance("SHA--1");
ƒ
Aggiornamento intermedio dell’input per la funzione di hashing [byte[] data]
sha.update(data);
sha.update(data);
ƒ
Impronta finale dell’input:
byte[] hash = sha.digest();