Skip to main content

Se eliminará SecurityManager de Java: qué significa para ti

Escrito por
feature java dto

15 de junio de 2023

0 minutos de lectura

El paquete java.security de la biblioteca del Java Development Kit (JDK) es uno de los más importantes. Sin embargo, a pesar de las actualizaciones constantes, sigue estando muy poco aprovechado.

Dada la creciente importancia de los marcos de ciberseguridad, incluido zero trust, es fundamental que los desarrolladores de Java conozcan las bibliotecas de seguridad de Java SE.

Como cualquier otro campo de la tecnología de la información, la ciberseguridad es impredecible. Al fin y al cabo, debe mantenerse al día con las últimas tendencias del ciberdelito. Una de las formas en que ha evolucionado (o involucionado, según a quién le preguntes) la seguridad de Java es con la eliminación de SecurityManager. Pero ¿por qué es importante? ¿Hay motivos reales para preocuparse? Este artículo te ayudará a responder estas preguntas.

La importancia de la seguridad en Java

Java se considera un lenguaje seguro por naturaleza gracias a funciones como la máquina virtual de Java (JVM), la administración de memoria, el sólido manejo de excepciones y la ausencia de punteros explícitos (*es decir*, referencias). A pesar de estas funciones integradas, es posible que los usuarios se muestren menos dispuestos a usarlo debido a vulnerabilidades de alto perfil, como Log4j.

Sin embargo, es importante tener en cuenta que muchas de estas vulnerabilidades están relacionadas con productos, terceros o desarrolladores (*es decir*, los desarrolladores no escriben código seguro). Aunque Java tiene (o tuvo) vulnerabilidades específicas del JDK, como la exposición de datos confidenciales y problemas de deserialización, muchas ya se resolvieron o están en proceso de resolverse. Por ejemplo, JDK 20 se lanzó con una optimización mejorada de las funciones intrínsecas de criptografía para plataformas específicas.

Por supuesto, esto no significa que Java se encargue automáticamente de toda la seguridad. Es responsabilidad del desarrollador escribir código seguro. Esto implica comprender las capacidades y limitaciones de los paquetes de seguridad integrados de Java; por lo general, no hace falta recurrir a API y bibliotecas de seguridad de terceros.

El JDK incluye funciones de seguridad de plataformas, criptografía, control de acceso y autenticación, comunicaciones e infraestructura de clave pública. Puedes explorar todas estas funciones en la guía para desarrolladores de seguridad oficial.

Mejorar cualquier plataforma o herramienta también implica eliminar funciones inseguras o innecesarias. Una de ellas es SecurityManager.

¿Qué es SecurityManager?

Java SecurityManager se diseñó como una autoridad federada para la seguridad de las aplicaciones. Se usa (o se usaba) para especificar políticas de seguridad y reglas para las aplicaciones Java, con el fin de garantizar que ciertas operaciones sean seguras. La clase Java.lang.SecurityManager existe desde JDK 1.0.

Al principio, SecurityManager era una clase abstracta. Sin embargo, con el tiempo dejó de serlo para facilitar su acceso y uso. Aunque se podía crear una instancia de un nuevo objeto SecurityManager con cada clase, esto no se ajustaba a las mejores prácticas de programación de Java. En su lugar, era necesario establecer una propiedad del sistema al ejecutar la aplicación:

java -Djava.security.manager MyAPP

Como alternativa, podías establecerlo creando directamente una instancia de un objeto SecurityManager y luego configurándolo como propiedad del sistema desde el código:

SecurityManager sm = new SecurityManager();
System.setSecurityManager(sm);

Luego, se podía obtener el SecurityManager del sistema desde otra clase con lo siguiente:

SecurityManager securityManager = System.getSecurityManager();

La clase SecurityManager consta principalmente de una serie de métodos de comprobación. Estos métodos verifican si determinadas operaciones de la aplicación pueden acceder a ciertos recursos. Podría decirse que el más útil es el método checkPermission, que verifica si una operación tiene permiso para usar ciertos recursos. Las políticas de permisos se definen y controlan mediante subclases directas y heredadas de la clase java.security.Permission.

En definitiva, SecurityManager simplifica la seguridad de las aplicaciones Java y es fácil de usar. Entonces, ¿por qué se marcó como obsoleto?

La historia de SecurityManager

Cada nueva versión de Java SE incluye muchas mejoras, gran parte de ellas gracias al Java Community Process (JCP) y a las propuestas de mejora del JDK. Estas últimas son la razón principal por la que SecurityManager se marcó como obsoleto y se programó para su eliminación.

En sus primeras etapas de uso, la clase SecurityManager se implementaba principalmente para definir políticas de seguridad para los applets, que la mayoría de las plataformas web ya no admiten. El navegador web proporcionaba el SecurityManager de cada applet.

La API de Java Applet finalmente se marcó como obsoleta con el lanzamiento de Java 9 en 2017, según lo establecido por JEP289. Sin embargo, aunque se marcó como obsoleta, no se programó su eliminación. Con el lanzamiento de Java SE 17, la API de Applet y sus clases relacionadas finalmente se marcaron como obsoletas y programadas para su eliminación, según lo especificado por JEP398.

Esta fue una forma de hacer avanzar el lenguaje de programación y la API. Las API heredadas como estas llegaron a un punto de obsolescencia que las volvió innecesarias para futuras versiones del JDK. Y como SecurityManager está estrechamente vinculado a la arquitectura de los applets, se eliminará por motivos similares.

¿Por qué se eliminará SecurityManager?

Hoy en día, SecurityManager ya no es la forma más eficiente de proteger el código Java del lado del cliente y del servidor. De hecho, la plataforma Java ofrece mecanismos más eficaces para estas tareas.

Cada nueva versión del JDK busca ser más segura por diseño que la anterior. Esto significa que muchas de las vulnerabilidades accidentales que SecurityManager intenta abordar ya no son relevantes.

Como la funcionalidad de SecurityManager no ha cambiado en la última década, no puede abordar muchas de las amenazas, debilidades y vulnerabilidades habituales que enfrentan los programadores en la actualidad. En realidad, nunca se diseñó ni creó para abordar los problemas de seguridad de hoy. Sin embargo, como todavía existe, debe probarse junto con todas las clases relacionadas.

Esto genera una carga de mantenimiento innecesaria. El tiempo y el esfuerzo que se requieren para mantener SecurityManager podrían dedicarse a probar clases y funciones que hoy son más relevantes para los desarrolladores. Aunque una de las mayores ventajas de la arquitectura de SecurityManager es su facilidad de comprensión, configurarlo puede ser difícil.

Como recordatorio, SecurityManager consta principalmente de una serie de métodos de comprobación. Por ejemplo, una función de seguridad útil es CheckPermission, que te permite validar los permisos de una aplicación o un sistema mediante tu archivo de políticas de Java. La estructura de una política que otorga al código de una aplicación acceso de lectura a un directorio sería así:

grant codeBase "file:/home/source/" {
    permission java.io.FilePermission "/resources/files", "read";
};

Esta configuración otorga al código (todos los archivos de clase) ubicado en file:/home/source/ acceso a todos los recursos del directorio relativo files. Para comprobar un permiso específico, debes crear una instancia de una subclase de `Permission` o de la clase `BasicPermission`. En última instancia, representa el conjunto de permisos del archivo de políticas. En este caso, se trata del objeto FilePermission:

FilePermission filePerm = new java.io.FilePermission("/resources/files", "read");

Como las políticas suelen depender del contexto, debes obtener un objeto que represente el contexto de control de acceso actual del código que ejecutas. Luego, puedes usar SecurityManager para comprobar los permisos en ese contexto:

AccessControlContext accessCon = AccessController.getContext();
 SecurityManager securityManager = System.getSecurityManager();
 securityManager.checkPermission (filePerm, accessCon);

Si tus políticas de lectura de archivos no permiten que tu código acceda al archivo de recursos, este código lanzará una SecurityException: la `AccessControlException`.

Aunque este proceso parece sencillo, tiene algunas desventajas. Puede ser difícil definir permisos y políticas detallados y granulares. Por ejemplo, ¿qué pasa si quieres que ciertas operaciones o clases tengan acceso de escritura a un archivo específico de un directorio cuyo acceso prohíben tus políticas?

Como solución alternativa, podrías separar los directorios de políticas, archivos de origen y recursos. Esto te obligaría a relacionar con cuidado y llevar un registro de cómo se vinculan tus permisos con cada una de tus políticas. Es muy ineficiente, sobre todo si intentas crear una aplicación con políticas y permisos detallados.

Tampoco es más fácil desarrollar bibliotecas y API que usen SecurityManager. Las bibliotecas que usan la arquitectura de SecurityManager requieren que otorgues a tu código algunos de los mismos permisos que ellas tienen. Esto significa revisar la documentación de la biblioteca para ver qué permisos otorga, suponiendo que cuente con documentación detallada.

Como alternativa, puedes otorgar todos los permisos a los archivos de la dependencia de la biblioteca. Sin embargo, esto no se ajusta a los principios modernos de seguridad zero trust (*es decir*, mínimo privilegio).

Para garantizar la portabilidad, tus aplicaciones deben ser funcionales, seguras y capaces de usar los recursos de manera eficiente. SecurityManager consume muchos recursos, sobre todo cuando usas o escribes una aplicación con una red compleja de permisos y políticas. De hecho, la JVM siempre se ejecuta con SecurityManager desactivado de forma predeterminada.

SecurityManager no solo está obsoleto desde el punto de vista funcional, sino que también dejó de ser relevante desde el punto de vista arquitectónico. Esto significa que no tendrá reemplazos directos. Entonces, ¿qué sigue?

El futuro de SecurityManager

Al momento de escribir este artículo, JDK 20 acababa de estar disponible de forma general y gran parte de la arquitectura de SecurityManager seguía intacta. Se lanzaron tres versiones desde que se propuso eliminar SecurityManager. Como está integrado con muchas clases y bibliotecas de Java, es difícil eliminarlo sin romper toda la API de Java. Incluso Jakarta EE tiene muchas funciones que dependen de la arquitectura de SecurityManager.

Esto significa que eliminarlo por completo no será fácil. El plan es hacerlo gradualmente y de forma segura; el proceso ya comenzó, con SecurityManager marcado para su eliminación en JDK 17. Además, la JVM advierte a los usuarios si se crea o habilita dinámicamente un SecurityManager.

Para JDK 18, SecurityManager ya estaba deshabilitado de forma predeterminada. Si los desarrolladores intentaban crear y establecer un SecurityManager (setSecurityManger), se generaba un error UnsupportedOperationException. Aunque todavía existe la funcionalidad para admitir código heredado que usa SecurityManager, quienes sigan usando esta arquitectura deberían considerar abandonarla.

El JDK ofrece alternativas para muchas de las funciones de SecurityManager. Por ejemplo, quienes quieran controlar los permisos de acceso al código nativo pueden usar la API de funciones foráneas y memoria (FFM), que se introdujo en JDK 20.

Alternativas a SecurityManager

El primer paso para desvincular tu código de Java Security Manager es identificar dónde se usa. Aunque sigue disponible en las versiones más recientes del JDK con soporte a largo plazo (LTS), las versiones 17 y 21, está marcado como obsoleto. Las organizaciones que planean actualizar desde versiones LTS anteriores, como JDK 11 u 8, deben tenerlo en cuenta. En última instancia, todo código obsoleto debe eliminarse o actualizarse, ya que no recibe buen mantenimiento y puede representar un riesgo de seguridad. Puedes usar jdeprscan para encontrar todo el código obsoleto en tus archivos de clase.

La única alternativa real a SecurityManager que viene lista para usar es la biblioteca de seguridad del JDK. Los desarrolladores deben familiarizarse con las directrices de Oracle para escribir código seguro en Java SE. En definitiva, escribir código seguro desde el principio es el primer paso para reducir las vulnerabilidades de tu proyecto.

Aunque es importante buscar API obsoletas, no es la única debilidad de seguridad que debes detectar. También es fundamental revisar las dependencias y bibliotecas de tu proyecto. Los desarrolladores suelen usar SecurityManager para monitorear y registrar los recursos a los que acceden sus aplicaciones. Para esto, puedes utilizar una solución de terceros, como Snyk.

Snyk es una herramienta de seguridad para desarrolladores que puedes integrar en tu entorno de desarrollo para analizar la seguridad del código y los contenedores. Analiza los archivos de configuración y manifiestos de tu proyecto para encontrar y marcar dependencias directas e indirectas con vulnerabilidades conocidas. Snyk corrige tus vulnerabilidades automáticamente al aplicar parches a los archivos de configuración y actualizar todas las dependencias. Puedes integrarlo en diversas herramientas y flujos de trabajo de desarrollo.

Snyk ofrece una interfaz de línea de comandos (CLI) que permite a los desarrolladores usarlo en la terminal o en un flujo de trabajo de integración continua y entrega continua (CI/CD). Puedes descargar e instalar la herramienta independiente de Snyk CLI y, una vez que la hayas configurado y hayas autenticado tu cuenta, puedes probar tus proyectos locales con el comando snyk test.

Además, puedes mantenerte al día sobre las nuevas vulnerabilidades que surjan con el comando snyk monitor. Con este comando, Snyk toma una instantánea de tu proyecto (que puedes ver en la aplicación web) y te envía notificaciones por correo electrónico para informarte sobre cualquier problema nuevo que se detecte en tus componentes.

Aquí tienes una breve demostración de los comandos snyk test y snyk monitor:

Windows PowerShell muestra a Snyk CLI probando y monitoreando un proyecto Maven, sin encontrar rutas vulnerables.

Sin embargo, aunque Snyk puede encontrar vulnerabilidades, sigue siendo importante seguir los principios básicos de programación segura para Java. Como dice el viejo refrán: «Más vale prevenir que curar». Por eso, es importante usar Snyk CLI durante el desarrollo junto con una herramienta de CI, como parte de un proceso DevSecOps sólido.

En los últimos años, la industria ha visto un aumento considerable de las vulnerabilidades de código abierto. Para mitigar y prevenir ataques, los desarrolladores deben revisar periódicamente la postura de seguridad de sus proyectos y flujos de trabajo. Herramientas como Snyk se actualizan con regularidad y te permiten automatizar el proceso de control de calidad y seguridad al integrarlas en tu pipeline de CI/CD.

Ahora que SecurityManager está en sus últimos días, quizá te tiente usar una biblioteca o API de Java de terceros con una arquitectura o un enfoque similar. Las bibliotecas de terceros siempre han representado uno de los mayores riesgos de seguridad. Si decides seguir ese camino, considera usar Snyk Open Source para asegurarte de que las dependencias de tu proyecto sean seguras.

Conclusión

En definitiva, SecurityManager está obsoleto. Sorprende que hayan tardado tanto en eliminarlo oficialmente. Y esto no es una mala noticia. Todo lo contrario: hará que la plataforma Java sea mucho más segura y menos redundante. SecurityManager nunca tuvo como propósito ser una herramienta general de ciberseguridad de la que depender.

Si quieres mejorar de forma más eficaz la postura de seguridad general de tus proyectos, considera usar una herramienta como Snyk. Puede ayudarte a incorporar confianza cero en tu flujo de trabajo de desarrollo. Además, puedes agregar el complemento de Snyk Code para IntelliJ para proteger tu código y garantizar su calidad en tiempo real.

Comienza con Capture the Flag

Aprende a resolver desafíos de Capture the Flag con nuestro taller virtual 101 a pedido.

Leer más

blog feature snyk container custom base recommendations
Blog

Presentamos Evo Agentic AppSec: seguridad al ritmo del desarrollo con IA

El desarrollo impulsado por IA supera el ritmo de los flujos de trabajo de seguridad tradicionales. Agentic AppSec de Snyk usa agentes de seguridad para encontrar, corregir y verificar vulnerabilidades de forma continua, mientras las personas definen el estándar.

blog feature ai violet
Blog

VulnBump: ¿Pueden los agentes de IA corregir dependencias vulnerables sin romper la compilación?

VulnBump prueba agentes de IA en 307 actualizaciones reales de dependencias. Una corrección cuenta solo si elimina la vulnerabilidad y mantiene en verde la compilación y las pruebas.

Blog

Los modelos de frontera encontraron las vulnerabilidades. Solo el atacante encontró las cadenas.

El análisis estático encontró las fallas, pero solo las pruebas de ataque en vivo demostraron cómo podían encadenarse para provocar brechas. Una comparación de Evo COS, Claude Security y Claude Code Security.