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.
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:
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:
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.
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:
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.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:
Es un permiso que asigna todos los demás permisos.
Permisos para el AWT (acceso al portapapeles, a los eventos, etc.).
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
.
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.
Permisos para manipular properties
.
Permisos para efectuar operaciones reflectivas. Son permisos sin acciones.
Permisos para tiempo de ejecución (acceso a ClassLoaders, SecurityManager, Threads, etc). Son permisos sin acciones.
Permisos relacionados con la seguridad. Son permisos sin acciones.
Permisos relacionados con la serialización de objetos. Son permisos sin acciones.
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.
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.