Página siguiente Página anterior Índice general

6.4 Dominios protegidos, modelo de permisos y políticas de seguridad

En este punto explicaremos que son los dominios protegidos, como funciona el modelo de permisos de Java 2 y como se definen las políticas de seguridad.

Dominios protegidos

El concepto de dominio protegido es fundamental para la seguridad de los sistemas. El alcance de un dominio está definido por el conjunto de objetos que estan directamente accesibles para un principal, donde principal es una entidad en el sistema informático a la que se le han asignado permisos. El cajón de arena del JDK 1.0 es un ejemplo de dominio de protección con límites fijos.

El concepto de dominio protegido proporciona un mecanismo adecuado para agrupar y aislar unidades de protección. Por ejemplo, se pueden separar dos dominios de forma que la interacción entre ambos únicamente sea posible a través de código del sistema o de un protocolo explícito para la comunicación entre ambos.

Los dominos protegidos se dividen generalmente en dos categorias:

  1. Dominos del sistema, que controlan el acceso a los recursos del sistema (sistema de archivos, acceso a la red, E/S).
  2. Dominios de aplicación, que controlan el acceso a los recursos de una aplicación.

Conceptualmente un dominio incluye un conjunto de clases cuyas instancias tienen asignados los mismos permisos. Los dominios de protección se determinan mediante la política de seguridad activa en cada momento.

El entorno Java mantiene una asociación entre el código (clases e instancias) y sus dominios de protección. Esta relación es de varios a uno, es decir, disitintas clases pueden pertenecer a un mismo dominio, pero cada clase sólo está asociada un dominio. Para los dominios de protección se emplea otra tabla que relaciona cada dominio con sus permisos correspondientes. Evidentemente esta asociación es de muchos a muchos, varios dominios pueden tener el mismo permiso y cada dominio puede tener multiples permisos.

Un hilo de ejecución puede trabajar únicamente en un dominio protegido o puede ir pasando del dominio de la aplicación al del sistema y viceversa. Esto tiene implicaciones importantes en la seguridad, se plantean dos escenarios:

  1. Si una aplicación accede al sistema y solicita una operación que requiere permisos del dominio del sistema, se debe garantizar que la aplicación no tendrá acceso directo al dominio del sistema, es decir, que su domino de protección no obtendrá ningún permiso del dominio del sistema.
  2. Si una clase del sistema invoca un método de la aplicación, es esencial que los permisos de ese método cuando se ejecute sean los del domino de la aplicación, no los del sistema.

En definitiva, el modelo de dominios protegidos debe garantizar que un dominio menos poderoso no pueda obtener permisos adicionales al invocar o ser invocado por otro dominio más poderoso.

Ocasionalmente será necesario que código fiable de acceso temporal a más recursos de los que normalmente están disponibles para la aplicación que lo invocó. Por ejemplo, una aplicación no tiene porque tener acceso directo a los ficheros que contienen los tipos de letra, pero la útilidad del sistema que muestra un documento debe conseguir esos tipos. Para solucionarlo se emplea el método doPrivileged, que está disponible en todos los dominios.

Cuando un fragmento de código llama al método doPrivileged, se considera que el conjunto de permisos activo incluye un permiso si lo permite el domino protegido del código invocante y todos los dominos en los que se entra a continuación.

Durante la ejecución, cuando se solicita acceso a un recurso del sistema, el código de gestión de recursos invoca directa o indirectamente a un método especial de la clase AccessControler que evalua la petición y decide si debe concederse o no el acceso. Si se concede el permiso la ejecución continua y si no se lanza una excepción de seguridad.

Modelo de permisos

Los permisos en Java son clases que representan accesos a recursos del sistema. La clase fundamental es java.security.Permission, que es una clase abstracta de la que se deben definir subclases para representar accesos específicos.

Un permiso consta de un objetivo y una acción, aunque puede omitirse cualquiera de los dos. Por ejemplo, para acceder al sistema de ficheros local el objetivo puede ser un directorio o un fichero y las acciones pueden ser: leer, escribir, ejecutar y borrar.

Generalmente, una clase de permiso pertenece al paquete en el cual será usada. Por ejemplo, el permiso que representa el acceso al sistema de ficheros local es java.io.FilePermission.

Como ejemplo de permiso, el siguiente fragmento de código se puede emplear para generar un permiso de lectura del archivo "abc" en el directorio /tmp:

perm = new java.io.FilePermission("/tmp/abc", "read");

Si queremos definir nuevos permisos es crucial implementar el método abstracto implies. Básicamente, la afirmación a implica b tiene el significado intuitivo, si una clase tiene el permiso a tiene tambien el permiso b. Esto es muy importante a la hora de tomar decisiones de control de acceso.

La clase abstracta java.security.Permission tiene asociadas dos clases importantes:

  1. La clase abstracta java.security.PermissionCollection, que representa una colección de objetos de tipo Permission de una misma categoría (como por ejemplo de acceso a ficheros), para simplificar el agrupamiento.
  2. La clase final java.security.Permissions, que representa una colección de colecciones de objetos Permission.

Antes del acceder a un recurso se toma la decisión de control de acceso al recurso, basada en los permisos que el código en ejecución tiene. Aunque cualquier código puede crear sus propios objetos de permisos, esto no implica que tales objetos obtengan los correspondientes permisos de acceso. Sólo los objetos de permisos que gestiona el sistema en tiempo de ejecución de Java obtienen los permisos que representan.

Los permisos definidos por el JDK 1.2 son:

AllPermission

Es un permiso que asigna todos los demás permisos.

AWTPermission

Permisos para el AWT (acceso al portapapeles, a los eventos, etc.).

FilePermission

Un permiso java.io.FilePermission representa permisos de acceso a archivos o directorios y consta de un nombre de ruta y un conjunto de acciones validas para esa ruta.

Si la ruta tiene el valor * se considera que el permiso se asigna a todos los ficheros del directorio acutal y si tiene el valor -, se refiere a los archivos del directorio actual y, recursivamente, a todos lo ficheros del directorio actual.

Las acciones posibles son: read, write, execute y delete.

NetPermission

Un permiso java.net.NetPermission es para varios permisos de red. Un permiso de red contiene un nombre pero no tiene lista de acciones, o se tiene el permiso o no se tiene.

PropertyPermission

Permisos para manipular properties.

ReflectPermission

Permisos para efectuar operaciones reflectivas. Son permisos sin acciones.

RuntimePermission

Permisos para tiempo de ejecución (acceso a ClassLoaders, SecurityManager, Threads, etc). Son permisos sin acciones.

SecurityPermission

Permisos relacionados con la seguridad. Son permisos sin acciones.

SerializablePermission

Permisos relacionados con la serialización de objetos. Son permisos sin acciones.

SocketPermission

Un permiso java.net.SocketPermission representa un acceso a la red a través de sockets. Un SocketPermission consta de una dirección de host y un conjunto de acciones especificando formas de conectar.

La especificación de la dirección del host se hace del siguiente modo:

host = (nombreHost | dirIP)[:rangoPuertos]
rangoPuertos = numPuerto | -numPuerto | numPuerto-[numPuerto]
El nombre del host puede ser según el DNS o en formato IP. El rango de puertos es opcional.

Las formas de conectar posibles son: accept, connect, listen y resolve.

En http://java.sun.com/products/jdk/1.2/docs/guide/security/permissions.html se pueden encontrar tablas con los permisos definidos en el jdk1.2 y las implicaciones de seguridad que tiene asignarlos.

Políticas de seguridad

En el JDK 1.2 las políticas de seguridad se especifican en uno o más ficheros de configuración de políticas. Estos ficheros especifican que permisos están habilitados para el código obtenido de los origenes de código especificados.

Un archivo de políticas de seguridad se puede escribir directamente con un editor de texto ascii o usando la herramienta policytool del JDK.

Por defecto hay un archivo de políticas del sistema y, opcionalmente, otro archivo de políticas del usuario.

El objeto Policy por defecto se inicaliza la primera vez que se invoca su método getPermissions() o cuando se invoca su método refresh(). La inicialización supone el análisis (parsing) de los archivos de configuración de políticas y la configuración del objeto Policy.

Se puede encontrar una discusión sobre las políticas de seguridad en la documentación sobre seguridad del JDK 1.2: http://java.sun.com/products/jdk/1.2/docs/guide/security/PolicyFiles.html.


Página siguiente Página anterior Índice general