Introducción al SecurityManager de Java

Parte superior de Java

Acabo de anunciar el nuevo curso Learn Spring , centrado en los fundamentos de Spring 5 y Spring Boot 2:

>> VER EL CURSO

1. Información general

En este tutorial, echaremos un vistazo a la infraestructura de seguridad incorporada de Java, que está deshabilitada de forma predeterminada. Específicamente, examinaremos sus componentes principales, puntos de extensión y configuraciones.

2. SecurityManager en acción

Puede ser una sorpresa, pero la configuración predeterminada de SecurityManager no permite muchas operaciones estándar :

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

Aquí, habilitamos la supervisión de seguridad mediante programación con la configuración predeterminada e intentamos conectarnos a google.com.

Entonces obtenemos la siguiente excepción:

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

Hay muchos otros casos de uso en la biblioteca estándar, por ejemplo, leer propiedades del sistema, leer variables de entorno, abrir un archivo, reflejar y cambiar la configuración regional, por nombrar algunos.

3. Caso de uso

Esta infraestructura de seguridad está disponible desde Java 1.0. Este fue un momento en el que los applets (aplicaciones Java integradas en el navegador) eran bastante comunes. Naturalmente, era necesario restringir su acceso a los recursos del sistema.

Hoy en día, los applets están obsoletos. Sin embargo, la aplicación de la seguridad sigue siendo un concepto real cuando existe una situación en la que el código de terceros se ejecuta en un entorno protegido .

Por ejemplo, considere que tenemos una instancia de Tomcat donde los clientes de terceros pueden alojar sus aplicaciones web. No queremos permitirles ejecutar operaciones como System.exit () porque eso afectaría a otras aplicaciones y posiblemente a todo el entorno.

4. Diseño

4.1. Gerente de seguridad

Uno de los componentes principales de la infraestructura de seguridad incorporada es java.lang SecurityManager . Tiene varios métodos checkXxx como checkConnect , que autorizaba nuestro intento de conectarnos a Google en la prueba anterior. Todos ellos delegados al método checkPermission (java.security.Permission) .

4.2. Permiso

Las instancias java.security.Permission representan solicitudes de autorización. Las clases estándar de JDK las crean para todas las operaciones potencialmente peligrosas (como leer / escribir un archivo, abrir un socket, etc.) y entregarlas a SecurityManager para la debida autorización.

4.3. Configuración

Definimos los permisos en un formato de política especial. Estos permisos toman la forma de subvenciones :

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

La regla codeBase anterior es opcional. No podemos especificar ningún campo allí o usarignedBy (integrado con los certificados correspondientes en el almacén de claves) o principal ( java.security.Principal adjunto al hilo actual a través de javax.security.auth.Subject ). Podemos usar cualquier combinación de esas reglas .

De forma predeterminada, la JVM carga el archivo de política del sistema común ubicado en < java.home> /lib/security/java.policy . Si hemos definido alguna política local de usuario en /.java.policy , la JVM la agrega a la política del sistema.

También es posible especificar un archivo de política a través de la línea de comando: - Djava.security.policy = / my / policy-file . De esa manera, podemos agregar políticas al sistema previamente cargado y a las políticas de usuario.

Hay una sintaxis especial para reemplazar todas las políticas del sistema y del usuario (si las hubiera) - doble signo igual: - Djava.security.policy == / my / policy-file

5. Ejemplo

Definamos un permiso personalizado:

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

y un servicio compartido que debe protegerse:

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"); } }

Si intentamos ejecutarlo con un administrador de seguridad habilitado, se lanza una excepción:

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)

Podemos crear nuestro archivo /.java.policy con el siguiente contenido e intentar volver a ejecutar la aplicación:

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

Funciona muy bien ahora.

6. Conclusión

En este artículo, verificamos cómo está organizado el sistema de seguridad JDK integrado y cómo podemos extenderlo. Aunque el caso de uso objetivo es relativamente raro, es bueno tenerlo en cuenta.

Como de costumbre, el código fuente completo de este artículo está disponible en GitHub.

Fondo de Java

Acabo de anunciar el nuevo curso Learn Spring , centrado en los fundamentos de Spring 5 y Spring Boot 2:

>> VER EL CURSO