Serie de documentos ¿Cómo hacer?
Aplicaciones Web seguras con Apache, OpenSSL, GPG y PHP
T.S.U. Leonardo Caballero
Grupo de Usuarios Linux de Mérida - GULMER
Web Site: http://www.gulmer.org.ve/
Linux User # 369081 / IRC Nick: macagua
E-mail: leonardocaballero@gmail.com
Web Site: http://lcaballero.8k.com/
Palabras clave
HowTo, Servidor Web Seguro, Apache, OpenSSL, PKI, Certificado Digital, PGP, GPG, Triatlon de Software Libre, Mérida.
Resumen
El presente HowTo describe los servicios y aplicaciones necesarias para mi “proyecto de software libre” que defendí en el “I Triatlon Regional de Software Libre Mérida” para lograr esto estuve 4 horas investigando en Internet y conseguí varios manuales, pero estaban desactualizados con respecto a mi distribución Debian GNU/Linux, o simplemente daban por entendido muchas cosas que yo no sabía, por lo que para resolver mi problema tuve que utilizar como mínimo 3 manuales que son diferentes en cuanto su distribución, versión de paquetes, entre otras, logre adaptarlo a mi solución. Esta dificultad en la documentación me da base para realizar este HowTo bajo las características de requerimientos que se citan el en mismo apartados.
El mismo aborda los siguientes temas: Introducción al tema, definiciones a cerca de HTTPS, RSA, Triple DES, X.509, OpenSSL, Mod_ssl, PGP, PGP y GPG. Luego se citan los requerimientos de software para que todo funcione. Seguidamente se explican los procedimientos de instalación y configuración de los servicios del proyecto. Además el desarrollo de la aplicación demostrativa con códigos fuentes se ofrecen recursos en la red.
Introducción
Este HowTo es sobre ¿Cómo hacer aplicaciones Web seguras con conexiones cifradas con SSL?. Así, quien quiera empezar a montarse en casa un pequeño “laboratorio de pruebas” ya tiene por donde empezar; el mismo describe los servicios y aplicaciones necesarias para mi “proyecto de software libre el cual defendí en el “I Triatlon Regional de Software Libre Mérida”; para lograr esto estuve 4 horas investigando en Internet y conseguí varios manuales pero estaban desactualizados con respecto a mi distribución Debian GNU/Linux, o simplemente daban por entendido muchas cosas que yo no sabía, por lo que para resolver mi problema tuve que utilizar como mínimo 3 manuales que son diferentes en cuanto su distribución, versión de paquetes, entre otras, logre adaptarlo a mi solución. A continuación les dejo algunas definiciones básicas que debe manejar para poder realizar el proceso con éxito
HTTPS.
Es la versión segura del protocolo HTTP, inventada en 1996 por Netscape Communications Corporation. No es un protocolo separado de HTTP. Se trata de una combinación de este último con un mecanismo de transporte SSL o TLS, garantizando una protección razonable durante la comunicación cliente-servidor. Es ampliamente utilizado en la red mundial (WWW o World Wide Web) para comunicaciones, como transacciones bancarias y pago de bienes y servicios.
El servicio utiliza el puerto 443 por TCP para realizar las comunicaciones (la comunicación normal para HTTP utiliza el 80 por TCP). El esquema URI (Uniform Resource Identifier o Identificador Uniforme de Recursos) es, comparando sintaxis, idéntico al de HTTP (http:), utilizándose como «https:» seguido del subconjunto denominado URL (Uniform Resource Locator o Localizador Uniforme de Recursos). Ejemplo: https://www.dominio.org/. [CEM-bot 2007].
RSA.
Es un algoritmo para el ciframiento de claves públicas el cual fue publicado en 1977, patentado en EE.UU. en 1983 por el el Instituto Tecnológico de Michigan (MIT). RSA es utilizado ampliamente en todo el mundo para los protocolos destinados al comercio electrónico. Sus siglas son acrónimo de los apellidos de sus autores, Ron Rivest, Adi Shamir y Len Adleman. [LordT 2007].
Triple DES.
También conocido como TDES, es un algoritmo que realiza un triple cifrado DES, desarrollado por IBM en 1978. Su origen tuvo como finalidad el agrandar la longitud de una clave sin necesidad de cambiar el algoritmo de ciframiento, lo cual lo hace más seguro que el algoritmo DES, obligando a un atacante el tener que triplicar el número de operaciones para poder hacer daño. A pesar de que actualmente está siendo reemplazado por el algoritmo AES (Advanced Encryption Standard, también conocido como Rijndael), sigue siendo estándar para las tarjetas de crédito y operaciones de comercio electrónico. [TXiKiBoT 2007].
X.509.
Es un estándar ITU-T (Estandarización de Telecomunicaciones de la International Telecommunication Union) para infraestructura de claves públicas (PKI, o Public Key Infrastructure). Entre otras cosas, establece los estándares para certificados de claves públicas y un algoritmo para validación de ruta de certificación. Este último se encarga de verificar que la ruta de un certificado sea válida bajo una infraestructura de clave pública determinada. Es decir, desde el certificado inicial, pasando por certificados intermedios, hasta el certificado de confianza emitido por una Autoridad Certificadora (CA, o Certification Authority). [Ignacioerrico 2007].
OpenSSL.
Es una implementación libre y código abierto, de los protocolos SSL (Secure Sockets Layer o Nivel de Zócalo Seguro) y TLS (Transport Layer Security, o Seguridad para Nivel de Transporte). Está basado sobre el extinto proyecto SSLeay, iniciado por Eric Young y Tim Hudson, hasta que éstos comenzaron a trabajar para la división de seguridad de EMC Corporation. [OpenSSL 2007].
Servidor HTTP Apache.
Es un software (libre) servidor HTTP de código abierto para plataformas Unix (BSD, GNU/Linux, etc.), Windows, Macintosh y otras, que implementa el protocolo HTTP/1.1 y la noción de sitio virtual. [VolkovBot 2007].
Mod_ssl.
Es un módulo para el servidor HTTP Apache, el cual provee soporte para SSL versiones 2 y 3 y TLS versión 1. Es una contribución de Ralf S. Engeschall, derivado del trabajo de Ben Laurie.
PGP.
Es un programa desarrollado por Phil Zimmermann y cuya finalidad es proteger la información distribuida a través de Internet, mediante el uso de criptografía de clave pública, así como facilitar la autenticación de documentos gracias a firmas digitales. Sus siglas significa Pretty Good Privacy (privacidad bastante buena). [Nolaiz 2007].
GPG.
GPG o Gnu Privacy Guard es una herramienta para cifrado y firmas digitales, que viene a ser un reemplazo del PGP (Pretty Good Privacy), pero con la principal diferencia que es software libre licenciado bajo la GPL y se puede ejecutar en Linux y en MS Windows. [RobotQuistnix 2007].
PHP
Es un lenguaje de programación usado normalmente para la creación de páginas web dinámicas. PHP es un acrónimo recursivo, que significa “PHP Hypertext Pre-processor” (inicialmente PHP Tools, o, Personal Home Page Tools), y se trata de un lenguaje interpretado. Últimamente también puede ser utilizado para la creación de otro tipo de programas incluyendo aplicaciones con interfaz gráfica, usando las bibliotecas Qt o GTK+. [Jarisleif 2007].
HTML
Es el acrónimo inglés de HyperText Markup Language, que se traduce al español como Lenguaje de Etiquetas de Hipertexto. Es un lenguaje de marcado diseñado para estructurar textos y presentarlos en forma de hipertexto, que es el formato estándar de las páginas web. Gracias a Internet y a los navegadores como Internet Explorer, Opera, Firefox, Netscape o Safari, el HTML se ha convertido en uno de los formatos más populares y fáciles de aprender que existen para la elaboración de documentos para la web. [CienciaAlPoder 2007].
Hojas de estilo en cascada
Las hojas de estilo en cascada (Cascading Style Sheets, CSS) son un lenguaje formal usado para definir la presentación de un documento estructurado escrito en HTML o XML (y por extensión en XHTML). [CienciaAlPoder 2007].
Cliente de correo electrónico.
Un cliente de correo electrónico, o también llamado en inglés mailer o Mail User Agent (MUA), es un programa de ordenador usado para leer y enviar e-mails. Originalmente, los clientes de correo electrónico fueron pensados para ser programas simples para leer los mensajes del correo de usuario, enviados por el agente de reparto de correo (MDA) conjuntamente con el agente de transferencia de correo (MTA), a un buzón local. [AlleborgoBot 2007].
Novell Evolution.
Evolution o Novell Evolution es un gestor libre de información personal y de trabajo en grupo para GNOME, desarrollado originalmente por Ximian ahora es parte oficial del escritorio de GNOME. Combina administración de correo electrónico, calendario, agenda y lista de tareas. Forma parte del conjunto GNOME Office. Su interfaz gráfica y funcionalidad imita bastante a la aplicación Microsoft Outlook. Evolution puede opcionalmente conectarse a servidores Microsoft Exchange, usando su interfaz web y un añadido conocido como Connector. [Estirabot 2007].
Requerimientos
No creo que hoy en día sea difícil instalar ambas cosas en cualquier distribución o plataforma estos son los únicos requisitos previos. Tampoco pienso que sea muy diferente en Windows. Los pasos que se detallan a continuación han sido realizados en los siguientes paquetes para GNU/Linux:
Es necesario disponer de una dirección IP pública (aunque para esta demostración no es necesario funciona con una IP privada) para cada sitio de red virtual que se quiera configurar con soporte SSL/TLS. Debido a la naturaleza de los protocolos SSL y TLS, no es posible utilizar múltiples sitios de red virtuales con soporte SSL/TLS utilizando una misma dirección IP. Cada certificado utilizado requerirá una dirección IP independiente en el sitio de red virtual.
El paquete mod_ssl (modulo de SSL para Apache 2) instala el fichero /etc/apache2/mods-enabled/ssl.conf, mismo que no es necesario modificar, puesto que se utilizarán ficheros de inclusión, con extensión *.conf, dentro del directorio /etc/apache2/mods-enabled/, a fin de respetar la configuración predeterminada y poder contar con la misma, que es funcional, brindando un punto de retorno en el caso de que algo saliera mal.
Instalación y configuración de los Servidor HTTP Apache, OpenSSL, GPGV y PHP.
Aunque supongo es igual que con distribuciones basadas en Debian, como siempre.
# aptitude install apache2
# a2enmod ssl
# aptitude install openssl
$ openssl genrsa -des3 > triatlon.key
La protección de la clave por contraseña (para lo que puede utilizar también AES) presenta el inconveniente de que tendrás que teclear esta contraseña cada vez que arranques el servidor y que si la olvida se acabó.
Por eso, si prefieres la comodidad a la máxima seguridad (por ejemplo, se trata de su servidor de pruebas) y está “seguro” de que la clave no va a caer en malas manos (o no importa), puedes optar por no proteger con contraseña y lo puede realizar con el siguiente comando:
$ openssl genrsa > triatlon.key
$ openssl req -new -key triatlon.key > triatlon.csr
Responde a las preguntas sobre país, provincia. ciudad, empresa, nombre y e-mail.
El fichero generado podrías enviarlo a una autoridad de certificación (como Verisign, de pago, o CACert, gratuita aunque no del agrado de Microsoft) para que lo firmaran y te enviaran su certificado, pero haremos algo aún mejor: ¡crearemos nuestra propia autoridad de certificación!.
Precaución: (el path a CA.pl puede ser distinto en su distribución) para localizarlo ejecute el siguiente comando:
$ locate CA.pl
Para generar la CA ejecute el siguiente comando:
$ /usr/lib/ssl/misc/CA.pl -newca
Presiona Enter y proporciona la que será contraseña de acceso a la clave privada de esta nueva autoridad. Proporciona país, provincia, ciudad, etc. para esta autoridad.
Enhorabuena. Ya eres el feliz propietario de una flamante “Autoridad de Certificación”, contenida en el nuevo directorio demoCA. El fichero cacert.pem contiene su clave pública, mientras que en el directorio private/cakey.pem dispones de la clave privada que te permitirá crear certificados para sus “clientes”.
$ openssl ca -policy policy_anything -out triatlon.crt -infiles triatlon.csr
Introduce la contraseña de su autoridad cuando se te pida. Pulsa ‘Y’ cuando se te pregunte si deseas firmar ‘Y’, también para ejecutar (commit) el cambio en su base de datos.
Vamos a generar también un certificado autofirmado para su propia autoridad certificadora (en el apartado 6 verás para qué). Acceda al directorio de su autoridad (demoCA) y escriba el siguiente comando:
$ openssl x509 -req -days 365 -in careq.pem -out cacert.crt -signkey ./private/cakey.pem
# cp triatlon.key /etc/apache2/
# cp triatlon.crt /etc/apache2/
Editar /etc/apache2/mods-enabled/ssl.conf para añadir el nombre, email del administrador y puerto de nuestro servidor y editar las líneas de clave y certificado para que digan así:
SSLCertificateFile /etc/apache2/triatlon.crt
SSLCertificateKeyFile /etc/apache2/triatlon.key
-
Copiar la configuración de sitios habilitados: No es necesario hacer un respaldo de el archivo en el directorio “sites-enabled” pero siempre es recomendado por si algo falla puede comparar con la configuración original. También nota que existe un enlace simbólico desde /etc/apache2/sites-enabled/000-default hasta /etc/apache2/sites-available/default. Intenta, respaldarlo en el directorio sites-available el archivo o en otra locación y los puede realizar con los siguientes comandos:
# cd /etc/apache2/sites-available
# cp /etc/apache2/sites-available/default default_original
-
Establecer un enlace simbólico necesario: El primer comando copia el archivo de la configuración por defecto para el puerto 80, para usar esta copia del archivo de configuración para el puerto 443. El segundo comando establece un enlace simbólico desde el fichero ’ssl’ en el directorio ’sites-available’ al fichero ’ssl’ en el directorio ’sites-enabled’. Esta metodología de enlazar con “enlaces simbólicos” entre dos directorios (como el mods-available y mods-enabled), es un explicado en fichero /etc/apache2/README. La idea general es que habilitemos ficheros de salida como enlaces simbólicos creados sus partes disponibles y lo puede realizar con los siguientes comandos:
# cp /etc/apache2/sites-available/default /etc/apache2/sites-available/ssl
# ln -s /etc/apache2/sites-available/ssl /etc/apache2/sites-enabled/ssl
-
Definiendo el “document roots”: Es la localización por defecto para las paginas HTML con la instalación inicial de Debian /var/www y allí existen en sitios no separados los archivos SSL. Yo prefiero separar para servir para paginas HTML básicas /var/www/html y páginas SSL en /var/www-ssl/htm. Como usted quiera trabajarlo no importa, pero para este paso creo los directorios y lo puede realizar con los siguientes comandos:
# cd /var/www
# mkdir html
# cd /var
# mkdir www-ssl
# cd www-ssl
# mkdir html
-
Configurar los “virtual hosts”: Aquí usted necesita definir en el archivo de configuración del Apache la IP de su servidor, nombre DNS (si existe) y el “document roots” (directorio raíz) que se creo en el anterior paso. Para configurar el puerto 80 del HTTP, ejecute el siguiente comando:
# vim /etc/apache2/sites-available/default
Nota: Observe lo siguiente que debes cambiar o agregar en la configuración de los “Virtual Host”.
NameVirtualHost *:80
<VirtualHost *:80>
ServerName localhost
DocumentRoot /var/www/html
Nota: Use su IP asignada o el nombre DNS seguido con “:80″. Si usted tiene una para el Nombre del Servidor.
El procedimiento es similar para HTTPS en el puerto 443, edite el /etc/apache2/sites-available/ssl con el siguiente comando:
# vim /etc/apache2/sites-available/ssl
Nota: Observe lo siguiente que debes cambiar o agregar en la configuración de los “Virtual Host”.
NameVirtualHost *:443
<VirtualHost *:443>
ServerName localhost
DocumentRoot /var/www-ssl/html
Nota: Use su IP asignada o el nombre DNS seguido con “:443″ .Si usted tiene una para el Nombre del Servidor.
# vim /etc/apache2/ports.conf
y añadir la siguiente linea:
Listen 443
-
Modificar el fichero /etc/hosts (si es necesario): Cuando arranque y detenga el servidor Apache, allí tal ves exista una advertencia como “Could not determine the server’s fully qualified domain name, using 127.0.1.1 for ServerName”. Debe tomar en cuenta esto si no tiene un nombre DNS para su servidor y esta usando una IP dinámico. Si este es su caso diríjase dentro del archivo /etc/hosts y realice los cambios siguientes: Básicamente usted debe agregar “localhost.localdomain” a la IP de 127.0.0.1 y cualquier nombre de su sistema que seleccionó cuando instaló su distribución (que asume usted no lo ha cambiado). La línea final abajo debe estar allí si tienes un IP estático y el correspondiente nombre del DNS registrado para esto. Si éste es el caso, en el paso anterior llamado “Configurar los virtual hosts” donde se colocó el ServerName, allí debe tener un valor que corresponda con el nombre del DNS, también indicado aquí y lo puede realizar con el siguiente comando:
# vim /etc/hosts
127.0.0.1 localhost localhost.localdomain {su nombre de su pc}
127.0.1.1 {su nombre de su pc}
{IP estática, si usted tienes uno} {Completo nombre del host DNS, si usted tiene uno}
# aptitude install gpgv
-
Iniciar sesión con usuario Apache: Si usted ha seguido los pasos previos debería estar iniciado como usuario “root”, si es así debe iniciar sesión desde la consola como el usuario “www-data” que es el usuario que usa el servidor Apache para la ejecución de solicitudes de los diferentes clientes hacia el servidor, usted lo puede realizar con el siguiente comando:
# su www-data
-
Generar llave(s) PGP: Se deben generar un nuevo par de llaves como un usuario sin privilegios de “root”, para que posteriormente pueda leer las claves del cliente de correo de su preferencia, usted lo puede realizar con el siguiente comando:
$ gpg –gen-key
Nota: Observa que el User Id o UID que colocas al generar la firma PGP lo debe cambiar o agregar en el archivo “mail.php” que verás en la sección “Mi solución al problema” en la variable llamada $desde, para que el interprete de PHP puede ejecutar el comando para firmar el mensaje que se envía cifrado con la firma que en este paso se esta generando.
$ gpg –list-keys
$ gpg –list-secret-keys
$ gpg –armor –output /tmp/tsl_publicas.asc –export nombre@proveedor
Nota: Observa que el e-mail nombre@proveedor es el mismo que coloco al generar la llaves PGP que realizó anteriormente en el paso llamado “Generar llaves PGP”.
$ gpg –armor –output /tmp/tsl_privadas.asc –export-secret-key nombre@proveedor
Nota: Observa que el e-mail nombre@proveedor es el mismo que coloco al generar la llaves PGP que realizo anteriormente en el paso llamado “Generar llaves PGP”.
$ exit
# aptitude install php5 libapache2-mod-php5
# /etc/init.d/apache2 restart
# vim /var/www-ssl/html/info.php
<?php
phpinfo();
?>
Ejecute su navegador preferido para probar nuestros servicios con la siguiente URL: https://localhost/info.php si muestra la información de la configuración de PHP5, podemos pasar al desarrollo de la aplicación para el proyecto. Si descarga el fichero info.php es que no esta configurado correctamente el modulo PHP5 con el servidor Apache 2, verifique que allá realizado exitosamente el paso llamado “Instalar PHP5”.
Desarrollo de la aplicación demostrativa
El enunciado propuesto para el “Proyecto de Software Libre” del “I Triatlon Regional de Software Libre Mérida” es el siguiente:
-
Realizar una aplicación web segura que envié por un formulario los siguientes datos:
-
Nombre
-
Cédula
-
Dirección
-
Teléfono.
La misma debe enviar los datos firmados mediante GPG al correo nux@ula.ve puede usar cualquiera de los recursos a continuación: PKI, GPG, Web service, CGI, entre otros.
Mi solución al problema
Bueno aquí va mi solución al problema la cual solvente usando el siguiente modelo:

Cuadro 1: Ilustración del proceso de flujo de trabajo de la aplicación
Obtener los fuentes del proyecto
Usted puede obtenerlo desde el siguiente vinculo: www-ssl.tar.gz
También en la secciones llamadas “Fichero index.html” y “Fichero mail.php” se encuentran detallados los código de la aplicación.
Fichero index.html
El fichero llamado “index.html” que posee el formulario de datos, donde los mismo son enviados a la aplicación llamada “mail.php”.
<?xml version=”1.0″ encoding=”utf-8″?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd”>
<html xmlns=“http://www.w3.org/1999/xhtml”>
<head>
<title>Prototipo de Triatlon de Software Libre</title>
<meta name=“GENERATOR” content=“Quanta Plus” />
<meta http-equiv=“Content-Type” content=“text/html; charset=utf-8″ />
<meta name=“KEYWORDS” content=“triatlon de software libre, software libre, ofimática, programación. administración gnu linux” />
<link rel=“stylesheet” type=“text/css” href=“styles/.css” />
</head>
<body style=“background-color : #c08300;”>
<h1 style=“color : #ffffff;”>Formulario de contacto</h1>
<form action=“mail.php” method=“post” enctype=“multipart/form-data”>
<fieldset title=“Ingrese sus datos en el siguiente formulario de contacto” style=“background-color : #c0b53c; width : 20%px;”>
<legend accesskey=“Prueba” style=”color : #ffffff;”> <strong><em>Formulario de contacto</em></strong> </legend><br />
<strong>Nombre completo:</strong> <input type=“text” name=“nombre” size=“50″ maxlength=“25″ alt=“Ingrese por favor su nombre completo” tabindex=“1″ /><br /><br />
<strong>Cédula de identidad:</strong> <input type=“text” name=“cedula” size=“10″ maxlength=“12″ alt=“Ingrese por favor su número de cédula de identidad” tabindex=“2″ /><br /> <br />
<strong>Dirección:</strong> <input type=“text” name=“direccion” size=“60″ maxlength=“100″ alt=“Ingrese por favor su dirección de domicilio completa” tabindex=“3″ /><br /><br />
<strong>Teléfono:</strong> <input type=“text” name=“telefono” size=“25″ maxlength=“25″ alt=“Ingrese por favor su teléfono” tabindex=“4″ /><br /><br />
<input type=“submit” name=“enviar” value=“Enviar” alt=”Haga clic aquí para enviar los datos” />
<input type=“reset” name=“limpiar” value=“Limpiar formulario” alt=”Haga clic aquí limpiar los datos del formulario” />
</fieldset><br /><br />
</form>
</body>
</html>
Fichero mail.php
Este fichero recibe los datos, se construye el mensaje y se firma con GPG del emisario antes de enviarlo al destinatario.
<?php
$nombre = $_POST['nombre'];
$cedula = $_POST['cedula'];
$direccion = $_POST['direccion'];
$telefono = $_POST['telefono'];
// ruta del GPG
$gpg = ‘/usr/bin/gpg’;
// Datos de origen
// Es el nombre del usuario que envía el correo
// pero también debe ser el mismo user id o UID
// del que firma el mensaje con su clave gpg
$desde = ‘Leonardo’;
// Datos de destinatario
// E-mail del destinatario
// $para = ‘nux@ula.ve’;
$para = ‘leonardo@localhost’;
// asunto
$asunto = ‘Correo del Mini Proyecto de Leonardo Caballero’;
// mensaje
$mensaje = “
<?xml version=“1.0“ encoding=“utf-8“?>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Strict//EN“ “http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd“>
<html xmlns=“http://www.w3.org/1999/xhtml“>
<head>
<title>$asunto</title>
<meta name=“GENERATOR“ content=“Quanta Plus“ />
<meta name=“AUTHOR“ content=“Leonardo Caballero“ />
<meta http-equiv=“Content-Type“ content=“text/html; charset=utf-8“ />
<meta name=“KEYWORDS“ content=“triatlon de software libre“ />
</head>
<body>
<table width=“100%“ cellspacing=“2“ border=“1“ cellpadding=“2“>
<caption>Datos enviados por un usuario</caption>
<thead>
<tr align=“center“>
<th>Nombre</th>
<th>Cédula</th>
<th>Dirección</th>
<th>Teléfono</th>
</tr>
</thead>
<tfoot>
<tr>