Los applets tienen fuertes restricciones de seguridad. No pueden acceder fuera de SU espacio de almacenamiento; por ejemplo, los applets normalmente se almacenan en un servidor remoto y se ejecutan en el puesto cliente, en este caso no podrán acceder al espacio de almacenamiento (disco) del cliente. Por lo misma razón un applet local no puede acceder a una base de datos remota.
Si tiene un applet que trata de acceder a un recurso fuera de su espacio de almacenamiento podemos obtener el siguiente mensaje:
Unable to connect to any hosts due to exception: java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:3306 connect,resolve)
El mensaje nos indica que se ha denegado el acceso para conectar al host (en este caso es 'localhost'). Lo que aparece entre paréntesis indica el permiso que necesita:
¿Por qué nos deniega el acceso? El concepto de applet fue diseñado con restricciones estrictas de acceso al sistema local (escritura, conexión, etc.). La idea de los creadores de Java era crear un lenguaje que tuviera limitaciones intrínsecas o estructurales para acceder al sistema local (el sistema sobre el que se descarga). El objetivo era evitar la creación de virus o gusanos con Java. Bajo Java 1.0 no se permitía en absoluto el acceso al sistema local (el equipo cliente, donde se ejecuta). Esto es cierto para un applet remoto; y en un applet local (applet almacenado en el disco local) sólo se puede acceder como mucho al espacio de directorios del applet. Pero con la versión 1.1 esta limitación se relaja: el applet firmado por una entidad de confianza tiene permiso de acceso.
Una applet tiene un administrador de seguridad por defecto (aunque el programador no especifique ninguno), que es una clase que determina los permisos del programa. El administrador comprueba si el thread actual puede realizar una serie de operaciones: crear un subproceso o un nuevo cargador de clases, modificar las propiedades del sistema, leer/escribir en un archivo o conectarse a un puerto específico.
¿Por qué una aplicación Java es menos restrictiva? Porque no instala administrador de seguridad,
con lo cual todas
las operaciones que antes mencionabamos están permitidas. Esto no quita para que pueda instalar un
administrador de seguridad por medio de setSecurityManager de la clase System.
Política de seguridad a partir de Java 1.2
Para más información sobre la politica de seguridad en Java 1.2: Tutorial de SUN
Con la versión 2.0 de Java tenemos un mecanismo de seguridad menos restrictivo, que nos permite afinar en la especificación de una política de seguridad, asociando a cada trozo de código (local o remoto) un tipo de permiso. Los trozos de código se denominan también base de código u origen de código. La sintaxis para especificar permisos es:
grant signedBy quien_firma_el_código, codeBase código_al_que_se_aplica_el_permiso {
permission tipo_de_permiso "destino", "acciones";
};
El significado de los elementos es:
Ejemplo en el que se especifican todos los archivos de código de .../jdbc/ o de uno de sus subdirectorios (si hubieramos usado .../jdbc/* se aplica sólo a todos los archivos del directorio):
grant signedBy "pepe", codeBase "file://c:/doc/java/jdbc/-" {
permission java.io.FilePermission "\\tmp\\archivo.txt", "write";
};
Ejemplo en el que los permisos se aplican a cualquier código:
grant {
permission java.net.SocketPermission "127.0.0.1:3306", "connect,resolve";
permission java.io.FilePermission "\\tmp\\archivo.txt", "write";
};
En nuestro caso, para resolver la denegación de acceso que vimos al principio hemos escrito:
permission java.net.SocketPermission "127.0.0.1:3306", "connect,resolve";
Ya tenemos bastante claro cómo definir el permiso, bien, pero ¿dónde se escribe el texto del permiso?
Archivos de política de seguridad
El archivo maestro para la política de seguridad es jre\lib\security\java.security. Hay varios aspectos en este archivo, pero nosotros nos vamos a centrar en algo muy concreto: es en java.security donde se especifican por orden los archivos de de política de seguridad. Supongamos, siguiendo nuestro ejemplo del applet, que tenemos un archivo denominado vista.policy situado en el mismo directorio de vista.html y que contiene:
grant {
permission java.net.SocketPermission "127.0.0.1:3306", "connect,resolve";
};
Este archivo indica que todo el código va a tener permiso de conexión a la máquina:puerto especificados. Tener este archivo ya nos permite hacer algo, para empezar, ejecutar sin problemas el applet que antes nos daba error. Lo que cambia es que ahora especificamos al AppletViewer el archivo .policy:
appletviewer -J-Djava.security.policy=vista.policy vista.html
¿Cómo conseguir que se ejecute desde un navegador (no sólo desde el AppletViewer)? Dijimos antes que es en jre\lib\security\java.security donde se especifican los archivos de políticas de seguridad. Además dijimos que los archivos se especifican por orden. La sintaxis es:
policy.url.n=URL_del_archivo_policy
jre\lib\security\java.security ya viene con dos referencias por defecto:
policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy
La primera URL indica que el primer archivo de política de seguridad que se aplicará será file:${java.home}/lib/security/java.policy, donde {java.home} suele ser el directorio jre (directorio de Java Runtime Edition). En el segundo ejemplo, {user.home} suele ser en un sistema XP c:\docs and settings\nombre_usuario.
Para terminar con nuestro ejemplo, podemos elegir:
grant {
...
permission java.net.SocketPermission "127.0.0.1:3306", "connect,resolve";
...
};
policy.url.3=file:c:/doc/java/jdbc02/class/vista.policy
Con el JDK viene una sencilla herramienta para modificar/crear archivos .policy: PolicyTool. Con esta herramienta ni tan siquiera es necesario conocer la sintaxis de grant { ... };
Puede acceder a un tutorial de SUN sobre el modelo de seguridad en Java 1.2.