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();