Introduzione a Java SecurityManager

Java Top

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO

1. Panoramica

In questo tutorial, daremo uno sguardo all'infrastruttura di sicurezza integrata di Java, che è disabilitata per impostazione predefinita. In particolare, esamineremo i suoi componenti principali, i punti di estensione e le configurazioni.

2. SecurityManager in azione

Potrebbe essere una sorpresa, ma le impostazioni predefinite di SecurityManager non consentono molte operazioni standard :

System.setSecurityManager(new SecurityManager()); new URL("//www.google.com").openConnection().connect();

Qui, abilitiamo in modo programmatico la supervisione della sicurezza con le impostazioni predefinite e proviamo a connetterci a google.com.

Quindi otteniamo la seguente eccezione:

java.security.AccessControlException: access denied ("java.net.SocketPermission" "www.google.com:80" "connect,resolve")

Esistono numerosi altri casi d'uso nella libreria standard, ad esempio la lettura delle proprietà del sistema, la lettura delle variabili d'ambiente, l'apertura di un file, la riflessione e la modifica delle impostazioni locali, solo per citarne alcuni.

3. Caso d'uso

Questa infrastruttura di sicurezza è disponibile da Java 1.0. Era un periodo in cui le applet, le applicazioni Java incorporate nel browser, erano piuttosto comuni. Naturalmente, era necessario limitare il loro accesso alle risorse di sistema.

Al giorno d'oggi, le applet sono obsolete. Tuttavia, l' applicazione della sicurezza è ancora un concetto reale quando esiste una situazione in cui il codice di terze parti viene eseguito in un ambiente protetto .

Ad esempio, considera che abbiamo un'istanza Tomcat in cui client di terze parti possono ospitare le loro applicazioni web. Non vogliamo consentire loro di eseguire operazioni come System.exit () perché ciò influenzerebbe altre applicazioni e possibilmente l'intero ambiente.

4. Progettazione

4.1. Manager della sicurezza

Uno dei componenti principali nell'infrastruttura di sicurezza integrata è java.lang SecurityManager . Ha diversi metodi checkXxx come checkConnect , che autorizzava il nostro tentativo di connettersi a Google nel test sopra. Tutti delegano al metodo checkPermission (java.security.Permission) .

4.2. Autorizzazione

Le istanze java.security.Permission rappresentano le richieste di autorizzazione. Le classi JDK standard le creano per tutte le operazioni potenzialmente pericolose (come la lettura / scrittura di un file, l'apertura di un socket, ecc.) E le consegnano a SecurityManager per la corretta autorizzazione.

4.3. Configurazione

Definiamo le autorizzazioni in uno speciale formato di policy. Queste autorizzazioni assumono la forma di voci di concessione :

grant codeBase "file:${{java.ext.dirs}}/*" { permission java.security.AllPermission; };

La regola codeBase sopra è facoltativa. Non possiamo specificare alcun campo lì o utilizzare signedBy (integrato con i certificati corrispondenti nel keystore) o principal ( java.security.Principal allegato al thread corrente tramite javax.security.auth.Subject ). Possiamo usare qualsiasi combinazione di queste regole .

Per impostazione predefinita, la JVM carica il file della politica di sistema comune situato in < java.home> /lib/security/java.policy . Se abbiamo definito una policy locale dell'utente in /.java.policy , la JVM la aggiunge alla policy di sistema.

È anche possibile specificare il file dei criteri tramite la riga di comando: - Djava.security.policy = / my / policy-file . In questo modo possiamo aggiungere policy al sistema precedentemente caricato e policy utente.

Esiste una sintassi speciale per sostituire tutti i criteri di sistema e utente (se presenti) - doppio segno di uguale: - Djava.security.policy == / my / policy-file

5. Esempio

Definiamo un'autorizzazione personalizzata:

public class CustomPermission extends BasicPermission { public CustomPermission(String name) { super(name); } public CustomPermission(String name, String actions) { super(name, actions); } }

e un servizio condiviso che dovrebbe essere protetto:

public class Service { public static final String OPERATION = "my-operation"; public void operation() { SecurityManager securityManager = System.getSecurityManager(); if (securityManager != null) { securityManager.checkPermission(new CustomPermission(OPERATION)); } System.out.println("Operation is executed"); } }

Se proviamo a eseguirlo con un gestore della sicurezza abilitato, viene generata un'eccezione:

java.security.AccessControlException: access denied ("com.baeldung.security.manager.CustomPermission" "my-operation") at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) at java.security.AccessController.checkPermission(AccessController.java:884) at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) at com.baeldung.security.manager.Service.operation(Service.java:10)

Possiamo creare il nostro file /.java.policy con il seguente contenuto e provare a rieseguire l'applicazione:

grant codeBase "file:" { permission com.baeldung.security.manager.CustomPermission "my-operation"; };

Funziona benissimo ora.

6. Conclusione

In questo articolo, abbiamo verificato come è organizzato il sistema di sicurezza JDK integrato e come possiamo estenderlo. Anche se il caso d'uso di destinazione è relativamente raro, è bene esserne consapevoli.

Come al solito, il codice sorgente completo di questo articolo è disponibile su GitHub.

Fondo Java

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO