No es un bug, es una característica no documentada

26/3/16

Procesos y servicios. Programación segura (V). Comunicación segura con Java

JSSE

JSSE (Java Secure Socket Extension) es un conjunto de paquetes que permiten el desarrollo de aplicaciones seguras en Internet. Proporciona un marco y una implementación para la versión Java de los protocolos SSL y TSL e incluye funcionalidad de encriptación de datos, autenticación de servidores, integridad de mensajes y autenticación de clientes.
Con JSSE, los desarrolladores pueden ofrecer intercambio seguro de datos entre un cliente y un servidor que ejecuta un protocolo de aplicación, tales como HTTP, Telnet o FTP, a través de TCP/IP.
Las clases de JSSE se encuentran en los paquetes javax.net y javax.net.ssl.

SSL

Las clas SSLSocket y SSLServerSocket representan sockets seguros y son derivadas de las ya familiares Socket  y ServerSocket respectivamente.

JSSE tiene dos clases SSLServerSocketFactory y SSLSocketFactory para la creación de sockets seguros. No tienen constructor, se obtienen a través del método estatico getDefault().

Para obtener un socket servidor seguro o SSLServerSocket

SSLServerSocketFactory sfact = (SSLServerSocketFactory)
SSLServerSocketFactory.getDefault();
SSLServerSocket servidorSSL = (SSLServerSocket)
sfact.createServerSocket(puerto);

El método createServerSocket(int puerto) devuelve un socket de servidor enlazado al puerto especificado. Para crear un SSLSocket:

SSLSocketFactory sfact = (SSLSocketFactory)
SSLSocketFactory.getDefault();
SSLSocket Cliente = (SSLSocket) sfact.createSocket(Host, puerto);

Archivo SERVIDORSSL.JAVA

import java.io.*;
import javax.net.ssl.*;

public class ServidorSSL {
     
      public static void main(String[] arg) throws IOException {
           
           
            //System.setProperty("javax.net.ssl.keyStore", System.getProperty("user.dir") + "\\AlmacenSSL");
            //System.setProperty("javax.net.ssl.keyStorePassword", "1234567");
           
           
            int puerto = 6000;
            SSLServerSocketFactory sfact = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
            SSLServerSocket servidorSSL = (SSLServerSocket) sfact.createServerSocket(puerto);
            SSLSocket clienteConectado = null;
            DataInputStream flujoEntrada = null; //FLUJO DE ENTRADA DE CLIENTE
            DataOutputStream flujoSalida = null; //FLUJO DE SALIDA AL CLIENTE
           
            for (int i = 1; i < 5; i++) {
                 
                  System.out.println("Esperando al cliente " + i);
                  clienteConectado = (SSLSocket) servidorSSL.accept();
                  flujoEntrada = new DataInputStream(clienteConectado.getInputStream());
                  // EL CLIENTE ME ENVIA UN MENSAJE
                  System.out.println("Recibiendo del CLIENTE: " + i + " \n\t" + flujoEntrada.readUTF());
                  flujoSalida = new DataOutputStream(clienteConectado.getOutputStream());
                  // ENVIO UN SALUDO AL CLIENTE
                  flujoSalida.writeUTF("SaIudos al cliente del servidor");
                 
            }// Fin de for
           
           
            // CERRAR STREAMS Y SOCKETS
            flujoEntrada.close();
            flujoSalida.close();
            clienteConectado.close();
            servidorSSL.close();
           
      }// Fin de main
     
}// Fin de ServidorSSL


Crea una conexión sobre un socket servidor seguro y que atenderá hasta cuatro conexiones de clientes que se identificarán con un certificado válido. El servidor espera las conexiones, de cada cliente que se conecta recibe un mensaje y a continuación le envía un saludo.

Archivo CLIENTESSL.JAVA

import java.io.*;
import javax.net.ssl.*;

public class ClienteSSL {
     
      public static void main(String[] args) throws Exception {
           
           
            //System.setProperty("javax.net.ssl.trustStore", System.getProperty("user.dir") + "\\UsuarioAlmacenSSL");
            //System.setProperty("javax.net.ssl.trustStorePassword", "890123");
           
            String Host = "localhost";
            int puerto = 6000;
           
            System.out.println("PROGRAMA CLIENTE INICIADO....");
            SSLSocketFactory sfact = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocket Cliente = (SSLSocket) sfact.createSocket(Host, puerto);
           
            // CREO FLUJO DE SALIDA AL SERVIDOR
            DataOutputStream flujoSalida = new DataOutputStream(Cliente.getOutputStream());
           
            // ENVIO UN SALUDO AL SERVIDOR   
            flujoSalida.writeUTF("Saludos al SERVIDOR DESDE EL CLIENTE");
           
            // CREO FLUJO DE ENTRADA AL SERVIDOR
            DataInputStream flujoEntrada = new DataInputStream(Cliente.getInputStream());
           
            // EL SERVIDOR ME ENVIA UN MENSAJE
            System.out.println("Recibiendo del SERVIDOR: \n\t" + flujoEntrada.readUTF());
           
            /*------------------------------------------------------------------------------
            //Información sobre la sesión SSL
            SSLSession session = ((SSLSocket) Cliente).getSession(); 
            System.out.println("Host: "+session.getPeerHost());
            System.out.println("Cifrado: " + session.getCipherSuite());
            System.out.println("Protocolo: " + session.getProtocol());
            System.out.println("IDentificador:" + new BigInteger(session.getId()));
            System.out.println("Creación de la sesión: " + session.getCreationTime());

            X509Certificate certificate = (X509Certificate)session.getPeerCertificates()[0];
            System.out.println("Propietario: " + certificate.getSubjectDN());
            System.out.println("Algoritmo: " + certificate.getSigAlgName());
            System.out.println("Tipo: " + certificate.getType());
            System.out.println("Emisor: " + certificate.getIssuerDN());
            System.out.println("Número Serie: " + certificate.getSerialNumber());
            ------------------------------------------------------------------------------*/
           
            // CERRAR STREAMS Y SOCKETS
            flujoEntrada.close();
            flujoSalida.close();
            Cliente.close();
           
      }// Fin de main
     
}// Fin de ClienteSSL

Envía un mensaje al servidor y visualiza el que el servidor le devuelve.

El servidor necesita disponer de un certificado que mostrar a los clientes que se conecten a él. Usaremos la herramienta keytool para crearlo, en el ejemplo le damos el nombre de AlmacenSSL y el valor de la clave es 1234567.

C:>keytool  -genkey -alias claveSSL -keyalg RSA –keystore AlmacenSSL -storepass 1234567

Para ejecutar el programa servidor es necesario indicar el certificado que se utilizará

C:>java -Djavax.net.ssl.keyStore=AlmacenSSL -Djavax.net.ssl.keyStorePassword=1234567 ServidorSSL

Antes de ejecutar el programa cliente necesitamos colocar el certificado en el keystore del usuario, para ello lo exportamos a un fichero, le llamamos por ejemplo CertificadoSSL.cer

C:>keytool -export -alias claveSSL -keystore AlmacenSSL -storepass 1234567 -file Certificado.cer

Una vez que tenemos el fichero exportado es necesario incorporarle al nuevo almacenamiento para permitir realizar la validación. A continuación se crea un keystore de nombre UsuarioAlmacenSSL con la clave 890123 y se incorpora el fichero de certificado Certificado.cer. Esto lo hacemos donde ejecutemos el cliente.

C:>keytool -import -alias claveSSL -file Certificado.cer –keystore UsuarioAlmacenSSL -storepass 890123

Para ejecutar el programa cliente escribimos lo siguientes

C:>java -Djavax.net.ssl.trustStore=UsuarioAlmacenSSL -Djavax.net.ssl.trustStorePassword=890123 ClienteSSL

En estos ejemplos para ejecutar el programa cliente y el servidor hemos establecido las propiedades JSSE desde la línea de comandos usando la sintaxis –Dpropiedad=Valor. También se pueden establecer desde el programa usando el método System.setProperty(String propiedad, String valor).


25/3/16

Procesos y servicios. Programación segura (IV). Criptografía con Java

Proveedores de servicios criptográficos

El API JCA (Java Cryptography Architecture, incluye la extensión criptográfica de Java JCE Java Cryptography Extension) incluída dentro del paquete JDK incluye dos componentes de software:
  • El marco que define y apoya los servicios criptográficos para que los proveedores faciliten implementaciones. Este marco incluye paquetes como
    • java.security
    • javax.crypto
    • javax.crypto.spec
    • javax.crypto.interfaces
  • Los proveedores reales, tales como Sun, SunRsaSign, SunJCE, que contienen las implementaciones criptográficas reales. El proveedore es el encargado de proporcionar la implementación de uno o varios algoritmos al programador. Los proveedores de seguridad se definen en el fichero java.security localizo en la carpeta java.home\lib\securityForman una lista de entradas con un número que indican el orden de búsqueda cuando en los programas no se especifica un proveedor.
    • security.provider.1=sun.security.provider.Sun
    • security.provider.2=sun.security.rsa.SunRsaSign
    • security.provider.3=com.sun.net.ssl.internal.ssl.Provider
    • security.provider.4=com.sun.crypyo.provider.SunJCE
    • security.provider.5=sun.security.jgss.SunProvider

JCA define el concepto de proveedor mediante la clase Provider del paquete java.security. Se trata de una clase abstracta que debe ser redefinida por clases proveedor específicas.

Tiene métodos para acceder a informaciones sobre las implementaciones de los algoritmos para la generación, conversión y gestión de claves y la generación de firmas y resúmenes, como el nombre del proveedor, el número de versión, etc.


Resúmenes de mensajes

Un message digest o resúmen de mensajes (también se le conoce como función hash) es una marca digital de un bloque de datos.

La clase MessageDigest permite a las aplicaciones implementar algoritmos de resumen de mensajes, como MD5, SHA-1 o SHA-256. Dispone de un constructor protegido, por lo que se accede a él mediante el método getInstance(String algoritmo).

Algunos métodos de la clase MessageDigest son:

24/3/16

Procesos y servicios. Programación segura (III). Seguridad en entornos Java

Antes de que la JVM comience el proceso de interpretación y ejecución de los bytecodes (código objeto) debe realizar una serie de tareas para preparar el entorno en el que el programa se ejecutará. Este es el punto en el que se implementa la seguridad interna de Java.

Hay tres componentes en el proceso:
  • El cargador de clases
  • El verificador de ficheros de clases
  • El gestor de seguridad

El cargador de clases

Es el responsable de encontrar y cargar los bytecodes que definen las clases. Cada programa Java tiene como mínimo tres cargadores:
  • El cargador de clases bootstrap que carga las clases del sistema (normalmente desde el fichero JAR rt.jar)
  • El cargador de clases de extensión que carga una extensión estándar desde el directorio jre/lib/ext
  • El cargador de clases de la aplicación que localiza las clases y los ficheros JAR/ZIP de la ruta de acceso a las clases (según está establecido por la variable de entorno CLASSPATH o por la opción –classpath de la línea de comandos)

El verificador de ficheros de clases

Se encarga de validar los bytecodes. Algunas de las comprobaciones que lleva a cabo son:
  • Que las variables estén inicializadas antes de ser utilizadas
  • Que las llamadas a un método coinciden con los tipos de referencias a objetos
  • Que no se han infrigido las reglas para el acceso a los métodos y clases privados, etc.

El gestor de seguridad

Es una clase que controla si está permitida una determinada operación.

Alguna de las operaciones que comprueban son las siguientes:
  • Si el hilo actual puede cargar un subproceso
  • Si puede acceder a un paquete específico
  • Si puede acceder o modificar las propiedades del sistema
  • Si puede leer desde o escribir en un fichero específico
  • SI puede eliminar un fichero específico
  • Si puede aceptar una conexión socket desde un host o número de puerto específico, etc.

Por defecto no se instala de forma automática ningún gestor de seguridad cuando se ejecuta una aplicación Java. En el siguiente ejemplo veremos la salida que produce el programa ejecutándolo sin gestor de seguridad y con gestor de seguridad. El programa muestra los valores de ciertas propiedades de sistema (usamos el método System.getProperty(propiedad) para mostrar los valores), la siguiente tabla describe alguna de las más importantes:

Archivo EJEMPLO1.JAVA

public class Ejemplo1 {
     
      public static void main(String[] args) {
           
            //propiedades de sistema en un array
            String t[] = {    "java.class.path", "java.home", "java.vendor",
                                   "java.version", "os.name", "os.version","user.dir",
                                   "user.home", "user.name"};
           
           
            System.setProperty ("java.security.policy", System.getProperty("user.dir") + "\\src\\_01SinConGestor\\Politica1.policy");
            System.setSecurityManager(new SecurityManager());
            for (int i = 0; i < t.length; i++) {
                 
                  System.out.print("Propiedad:" + t[i]);
                  try {
                        String s = System.getProperty(t[i]);     //valor de la propiedad
                        System.out.println("\t==> " + s);
                  } catch (Exception e) { System.err.println("\n\tEXcepción " + e.toString()); }
           
            }//Fin de for
      }//Fin de main
}//Fin de Ejemplo1

Archivo POLITICA1.POLICY (para política de permisos)

grant {
      permission java.util.PropertyPermission "java.class.path", "read";
      permission java.util.PropertyPermission "java.home", "read";
      permission java.util.PropertyPermission "user.home", "read";
      permission java.util.PropertyPermission "user.name", "read";
      permission java.util.PropertyPermission "user.dir", "read";
      permission java.util.PropertyPermission "on.version", "read";
};



18/3/16

Procesos y servicios. Programación segura (II)

1:18 Posted by Inazio Claver No comments
Proceso general de cifrado y descrifrado de mensajes.
  • Si a un texto legible se le aplica un algoritmo de cifrado, que en general depende de una clave, esto arroja como resultado un texto cifrado que es el que se envía o guarda. A este proceso se le llama cifrado o encriptación.
  • Si a ese texto cifrado se le aplica el mismo algoritmo, dependiente de la misma clave o de otra clave (esto depende del algoritmo), se obtiene el texto legible original. A este segundo proceso se le llama descrifrado o desencriptación.


3 clases de algoritmos criptográficos.
  • Funciones de una sola vía (o funciones Hash). Practicamente cualquier protocolo las usa para procesar claves, encadenar una secuencia de eventos, o incluso autenticar eventos y son esenciales en la autenticación por firmas digitales. Por ejemplo MD5 y SHA-1

  • Algoritmos de clave secreta o de criptografía simétrica, como DES, Tripe DES, AES.

17/3/16

Procesos y servicios. Programación segura (I). Buenas prácticas en programación

2:52 Posted by Inazio Claver 1 comment
1. Informarse
  • Una forma de evitar fallos es estudiar y comprender los erroes que otros han cometido a la hora de desarrollar software.
  • Internet es el hogar de una gran variedad de foros públicos donde se debaten con frecuencia problemas de vulnerabilidad de software.
  • Leer libros y artículos sobre prácticas de codificación segura, así como análisis de los defectos del software.
  • Explorar el software de código abierto, hay cantidad de ejemplos de cómo llevar a cabo diversas acciones, sin embargo, también se pueden encontrar numerosos ejemplos de cómo no se deben hacer las cosas.

6/3/16

Acceso a datos. Neodatis

2:37 Posted by Inazio Claver , 17 comments
Neodatis ODB es una base de datos orientada a objetos con licencia GNU muy simple que actualmente corre en los lenguajes Java, .Net, Google Android, Groovy y Scala.

Con Neodatis podemos evitar la falta de impedancia entre los mundos orientados a objetos y los relacionales, ya que actúa como una capa de persistencia transparente para Java, .Net y Mono.

Neodatis ODB soporta consultas nativas, es decir, podemos lanzar una consulta directamente desde Java, por ejemplo.
Además es bastante simple e intuitivo. Los objetos pueden ser añadidos fácilmente a la base de datos, lo que requiere clases no repetitivas y que las clases ya existentes no puedan modificarse.


También cuenta con un explorador ODB, una herramienta gráfica para navegar, consultar, actualizar y borrar objetos, así como la importación / exportación de bases de datos desde y hacía archivos XML.

4/3/16

Procesos y servicios. RMI (III). El ejercicio de la hipoteca

18:24 Posted by Inazio Claver , No comments
Este ejercicio fue el propuesto en clase de Procesos y Servicios para comprobar si se ha comprendido la sección de RMI. Es decir, vamos a ver como se desarrolla  un RMI básico implementando la teoría vista hasta ahora.

Ejercicio de la Hipoteca

Esta es la fórmula para el cálculo de la cuota mensual de una hipoteca.

Procesos y servicios. RMI (II)

13:06 Posted by Inazio Claver , No comments
(Puedes leer la primera parte aquí)

Introducción a las aplicacione RMI

Las aplicaciones RMi normalmente comprenden dos programas separados: un servidor y un cliente. Una aplicación servidor típica crea un montón de objetos remotos, hace accesibles unas referencias a dichos objetos remotos, y espera a que los clientes llamen a estos métodos u objetos remotos. Una aplicación cliente típica obtiene una referencia remota de uno o más objetos remotos en el servidor y llama a sus métodos.

RMI proporciona el mecanismo por el que se comunican y se pasan información del cliente al servidor y viceversa. Cuando es una aplicación algunas veces nos referimos a ella como Aplicación de Objetos Distribuidos

Objetos distribuidos

Elementos principales:
  • Interfaces remotas
  • Objetos remotos
  • Objetos serializables
  • Stubs
  • Servicio de nombres

Interfaces remotas. Es una interfaz acordada entre el servidor y el cliente. Un método que el cliente puede invocar.
Las clases de los parámetros y del resultado han de ser serializables (en Java simplemente una interfaz) o remotos.

Un objeto se convierte en remoto implementando un interface remoto, que tenga estas características.
Un interface remoto desciende del interface java.rmi.Remote.

Cada método del interface declara que lanza una java.rmi.RemoteException además de cualquier excepción específica de la aplicación.

Objetos remotos. Son objetos cuyos mensajes pueden ser invocados remotamente (desde objetos corriendo en otro proceso. En el caso de Java sería desde otra JVM).

Los objetos remotos deben implementar uno o varios interfaces remotos.

La clase del objeto remoto podría incluir implementaciones de otros interfaces (locales o remotos) y otros métodos (que sólo estarán disponibles localmente). Si alguna clase local va a ser utilizada como parámetro o cómo valor de retorno de alguno de esos métodos, también debe ser implementanda.

Objetos serializables. El RMI utiliza el mecanismo de serialización de objetos para transportar objetos entre máquinas virtuales. Implementar Serializable hace que la clase sea capaz de convertirse en un stream de bytes auto-descriptor que puede ser utilizado para reconstruir una copia exacta del objeto serializado cuando el objeto es leído desde el stream.

Stubs. Actúan como referencias a objetos remotos en el cliente. Es una clase usada por el cliente en sustitución de la remota.

Su clase es generada automáticamente a partir de la interfaz, e implementa la interfaz remota.

La implementación de cada operación envía un mensaje a la máquina virtual que ejecuta el objeto remoto y recibe el resultado, retransmitiendo llamadas desde el cliente hacia el servidor y siendotransparente al código del cliente.

Cuando un cliente invoca una operación remota que devuelve una referencia a un objeto remoto, obtiene una instancia del stub correspondiente.

Servicio de nombres. Permite asociar nombres lógicos a objetos.
El servidor asocia un nombre a un objeto, el cliente obtiene una referencia al objeto a partir del nombre (stub), y así se conseguiría el objetivo, tener transparencia de localización. 

Pasaje de objetos

El intercambio de objetos en la ejecución de un método en un objeto remoto puede ocurrir cuando:

  • Un cliente pasa objetos como parámetro pues así lo requiere el signature del método. El server recibe y puede manipular esos objetos.
  • El servidor reponde a la ejecución de un método a partir de un objeto. El cliente puede utilizar ahora ese objeto que recibe como respuesta.

Cualquiera de estos objetos (parámetros o respuesta) deben ser remotos y si no lo son deben ser serializables.

Si son remotos:
  • Estará tipado con una clase que extiende de UnicastRemoteObject.
  • Se pasan por referencia.
  • Los objetos remotos se convierten en stubs al pasar del servidor al cliente. Si no son objetos que se pueden acceder de manera remota (deben al menos ser serializables):
  • No están tipados con una clase que extienda UnicastRemoteObject (o alguna que indique que es remoto).
  • Deben implementar java.io.Serializable (de lo contrario se produce una excepción).
  • Son pasados por valor.
  • RMI se ocupa de la serialización de forma transparente para el desarrollador.
Ejemplo RMI



3/3/16

Acceso a datos. Bases de datos orientadas a objetos

2:37 Posted by Inazio Claver , No comments
(Fragmento obtenido de la Universidad de Los Andes, Venezuela)

Condiciones en las que nacen los SGBDR (años 60 – 70)

Uniformidad. Muchos datos estructurados de forma similar.
Orientación a Registros. Datos básicos organizados en registros de longitud fija.
Datos pequeños. Registros cortos, de 80 bytes o menos.
Campos atómicos. Cortos, indivisibles y de longitud fija.
Transacciones cortas. Tiempo de ejecución medido en fracciones de segundos / sin interacción del usuario.
Esquemas Conceptuales Estáticos. El esquema de la BD se cambia con muy poca frecuencia.
Procesamiento por Lotes. Poca interacción con el usuario.
Aplicaciones Casi Inexistentes. O a muy bajo nivel, embebidas e implementadas en el SGBD.

Con el tiempo, debido a la mayor capacidad de cómputo de los procesadores, mayor cantidad de memoria principal y secundaria y a la reducción generalizada de los costos del hardware fue posible desarrollar nuevos tipos de aplicaciones.
  • Diseño Asistido por Computador (CAD)
  • Ingeniería de Software Asistida por Computador (CASE)
  • Bases de datos de Multimedios
  • Sistemas de Información de Oficina
  • Sistemas de Información / Aplicaciones Empresariales
  • Sistemas Expertos de Bases de Datos (el cielo es el límite)

Nuevos tipos de aplicaciones, más capacidad de cómputo, más memoria principal y secundaria, implica que se producen cambios en la forma en que se ven y usan los SGBD.


Nuevas necesidades

Nuevas capas de aplicación
  • Reglas más complejas asociadas mucho más a nivel de aplicación (general) que a nivel de tuplas.
  • Mayor interacción (y más compleja) entre el usuario y la aplicación.
  • Transacciones de larga duración (en parte por el punto anterior).

Información más compleja à Objetos
Comportamiento asociado a la información à Objetos
Reducir la impedancia entre las nuevas capas de aplicación (Objetos) y el almacenamiento persistente de los datos (Relacional).

Sistemas de Gestión de BD Orientados a Objetos

Un Sistema de Gestión de Base de Datos Orientado a Objetos (SGBDOO) es un SGBD que integra de forma transparente características de las bases de datos (almacenamiento y acceso a la información, entre otros) con características de los lenguajes de programación de aplicación orientados a objetos.

Es decir, el SGBDOO se puede ver como una extensión que le da características de persistencia a algunos objetos de un lenguaje orientado a objetos, o como una extensión que añade características orientación a objetos a un Sistema de Gestión de Bases de Datos.

¿Cuál es la idea?