A
secure web tunnel method
English
Rubén Cisneros <cisneror at tb-solutions.com>
Pablo J. Royo <royop
at tb-solutions.com>
6. Creación de una tubería entre dos servidores web
7.
Experimental solutions and Internals
DOWNLOAD: patch_SPipe_0.1.4.gz README.SPipe
PÁGINA EN SOURCEFORGE: http://sourceforge.net/projects/spipe/
EJEMPLO CONCRETO: Creación de una tubería segura para POP3 y SMTP
EJEMPLO CONCRETO 2: Creación de una tubería segura para VNC o Terminal Server
SPipe (“Secure Pipe”) es una extensión del paquete mod_ssl para Apache, que permite a los usuarios obtener la funcionalidad de un servidor web y la de un túnel a otro servidor. Sus características son estas:
· Permite redirigir protocolos seguros no https a un servicio determinado.
· Permite utilizar un único puerto de entrada seguro a la red corporativa.
· Permite descifrar el protocolo entrante, y reenviarlo cifrado con una clave distinta a otro servicio tras el servidor web.
· Permite mostrar las cabeceras del protocolo https entrante.
· Permite habilitar otros puertos utilizando virtual-host, de forma que se puede dar servicio a multitud de aplicaciones con un único servidor Apache.
· Permite la creación de una tubería de comunicación segura, utilizando SSL, entre un cliente y un servidor que no hablen SSL, creando un canal de comunicación seguro fuera de las redes corporativas tanto del cliente como del servidor.
· Permite, para determinados protocolos, configurar en función del protocolo entrante a qué servicio se dirige la petición (EXPERIMENTAL).
Es una solución sencilla que permite utilizar el mismo servidor web corporativo de una entidad como puerta de acceso seguro a servidores internos que no utilizan HTTP como protocolo, a la vez que se permite el funcionamiento normal del servidor web para todas las peticiones HTTP.
La última versión del parche (v.0.1.2) funciona tanto en entornos UNIX como WIN32. Aunque este parche sólo es operativo para la versión 2.8.16 de mod_ssl que funciona bajo la versión 1.3.29 de Apache.
Por ejemplo, es posible descargar el correo de manera segura de un servidor de correo, situado tras el servidor Web, que no utiliza un protocolo seguro (SSL) para proporcionar los mensajes. Lo mismo puede decirse de cualquier protocolo no HTTP.
En este ejemplo, el usuario dispone de un agente de correo con capacidad para usar SSL, el servidor Web ha llevado a cabo toda la negociación inicial del protocolo seguro SSL y ha descifrado el protocolo, reenviando el protocolo ya en plano al servicio POP3 para descargar los mensajes.
Una configuración de Apache para esto sería la siguiente:
<VirtualHost *:4110>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot
/www/docs/dummy-host.example.com
ServerName
dummy-host.example.com
ErrorLog
logs/dummy-host.example.com-error_log
CustomLog
logs/dummy-host.example.com-access_log common
SSLEngine on
SSLCertificateFile
certs/server.crt
SSLCertificateKeyFile
certs/server.key
#This
directive is for showing headers
SSLSPipeShowHeaders
#
POP3 server
SSLSPipeUrl
pop3.dummy-host.remote.com:110
#Timeout
SSLSPipeWait
1
</VirtualHost>
Como vemos, no es necesario configurar ni crear certificados para el servidor de correo POP3, y sin embargo la descarga ha sido segura.
También existe la posibilidad de habilitar otro puerto con otro virtual-host que sirva de servidor de correo entrante SMTP. De este modo podríamos enviar y recibir el correo de forma segura a través del servidor web. En este caso se añadiría a la configuración:
<VirtualHost *:4025>
ServerAdmin
webmaster@dummy-host.example.com
DocumentRoot
/www/docs/dummy-host.example.com
ServerName
dummy-host.example.com
ErrorLog
logs/dummy-host.example.com-error_log
CustomLog
logs/dummy-host.example.com-access_log common
SSLEngine on
SSLCertificateFile certs/server.crt
SSLCertificateKeyFile certs/server.key
#This directive is for showing headers
SSLSPipeShowHeaders
#SMTP server
SSLSPipeUrl
smtp.dummy-host.remote.com:25
#Timeout
SSLSPipeWait
1
</VirtualHost>
Pero la principal ventaja estriba en que al pasar la comunicación por el propio servidor web corporativo, no es necesario tener un servicio diferente en otro puerto o dirección, y por tanto no deben abrirse o configurarse más puertos y/o direcciones en el firewall. Ésta es la principal diferencia con el excelente paquete, también OpenSource, STunnel.
Si está ya funcionando un servidor web Apache en un puerto, sólo es necesario recompilar el paquete mod_ssl después de aplicar el parche de SPipe, sin reconfigurar ni recompilar el núcleo de Apache. Lo cual es una gran ventaja.
Como requisito principal SPipe requiere que el núcleo de Apache este compilado con Extended API (EAPI). Esto es un requisito no restrictivo, puesto que para tener mod_ssl instalado en Apache es necesario que haya sido compilado con EAPI. Por ello, no se requiere la recompilación del núcleo de Apache si ya se está usando mod_ssl.
El servidor remoto al que se va a conectar debe utilizar un protocolo SSL puro (o uno sin SSL). Por ello, SPipe no funciona para redirigir tráfico contra servidores como SSH, ya que utilizan un protocolo propio de conexión segura que no tiene nada que ver con SSL.
SPipe requiere que esté instalado Apache con el módulo mod_ssl habilitado, por ello, en sistemas sin Apache es necesario configurarlo y compilarlo. Para indicar los pasos a seguir, utilizamos la siguiente notación:
EU.................. Comando que debe ser ejecutado por los ciudadanos de Europa
ALL................ Comando que debe ser ejecutado por todo el mundo, independientemente de la localización
OPTIONAL.... Comando opcional y no necesario realmente
SHARED....... Comando opcional, pero necesario para que mod_ssl sea un objecto dinámico (.so)
En primer lugar debemos de bajarnos los fuentes de Apache, mod_ssl y OpenSSL (ver referencias al final de la página), y los descomprimimos. Después configuramos la librería de OpenSSL con las siguientes instrucciones:
$ cd openssl-0.9.x ALL
$ sh config \ ALL
> no-idea \ EU
> no-threads \ OPTIONAL
> -fPIC
Posteriormente configuramos el paquete mod_ssl, para ello:
$ cd mod_ssl-x.x.x-x.x.x
$ ./configure \ ALL
> --with-apache = /path/to/apache/source \ ALL
> --with-ssl = /path/to/openssl \ ALL
> --with-crt = /path/to/your/server.crt \ OPTIONAL
> --with-key = /path/to/your/server.key \ OPTIONAL
> --prefix = /path/to/apache \ ALL
> --enable-shared = ssl \ SHARED
[...more mod_ssl options...] OPTIONAL
Por último, si queremos instalar el servidor web Apache debemos ejecutar las siguientes instrucciones:
$ ./configure \ ALL
> --prefix = /path/to/apache \ ALL
> --enable-rule = EAPI \ ALL
> --enable-rule = SHARED_CORE \ SHARED
> --enable-module = so \ SHARED
> --enable-shared = ssl \ SHARED
[...more Apache options...] OPTIONAL
Ahora sólo nos queda instalar SPipe. La instalación de SPipe es sencilla, únicamente hay que aplicar el parche SPipe al código fuente de mod_ssl. Para ello, hay que realizar la siguente llamada:
$ cd apache_x.x.x/src/modules/
$ patch < patch_SPipe_x.x
o
$ patch –i patch_SPipe_x.x
De este modo, se aplica el parche de SPipe al código de mod_ssl. Ahora, tenemos que compilar el paquete con make:
$ cd ssl
$ make
Por último, hay que copiar la librería creada (libssl.so) al directorio de Apache y reiniciar le demonio de Apache, esto se hace con:
$ cp libssl.so /path/to/apache/libexec
$ /path/to/apache/bin/apachectl stop
$ /path/to/apache/bin/apachectl startssl
El funcionamiento de SPipe es muy simple. Utiliza unas variables de configuración de Apache que permiten indicar los parámetros de configuración de SPipe. Estas directivas se aplican del mismo modo que se aplican las propias de mod_ssl. Es decir, en la misma sección del fichero de configuración httpd.conf en que se haya configurado mod_ssl.
Estas directivas son introducidas dentro de un virtual-host, por lo que podríamos tener varios virtual-host, uno para cada servicio. Dichas variables de configuración son las siguientes:
· SSLSPipeUrl <host:port> : Esta directiva permite indicar el servidor y puerto destino al que se conectará en caso de que la petición no sea HTTP. También se puede indicar en esta directiva si los datos recibidos deben ser reenviados en plano al servidor destino, o se debe volver a codificar con SSL de nuevo. Para esto se indica con una ‘s’ detrás del puerto, por ejemplo: “server:4443s”.
· SSLSPipeShowHeaders : Sirve para “tracear” las cabeceras de la petición HTTP en el fichero de log de errores de Apache. De este modo podemos tener un control del tráfico de peticiones al servidor web si nos interesa.
· SSLSPipeInputNoSSL : Con esta directiva indicamos que todo lo que llega al servidor web va a llegar en plano, y se debe codificar con SSL para enviarlo al servidor correspondiente. Cuando esta directiva está presente se ignoran las llamadas HTTP.
· SSLSPipeWait <timer> : (EXPERIMENTAL) Directiva que, permite marcar el tiempo, en segundos, que se esperará hasta que llegué un mensaje de petición del cliente. Si en el tiempo indicado no ha llegado dicho mensaje SPipe se conecta al servidor indicado por la directiva SSLSPipeUrl.
En el futuro, puede ser posible añadir a estos parámetos una pequeña tabla de configuración que permita asignar un servicio distinto a cada protocolo, al que se redirigirá la conexión dependiendo del primer paquete del cliente.
6.
Creación de una tubería entre dos servidores web
Otra de las funcionalidades que implementa SPipe es la creación de una tubería segura de comunicación por la que los datos irán cifrados, aunque el cliente original y el servidor destino no hablen SSL. Para ello se requiere dos servidores habilitados con SPipe.
Supongamos que nuestra empresa desea acceder de manera segura por telnet a un servidor telnet remoto, situado por ejemplo en otra delegación de nuestra compañía. No podemos utilizar SSH porque los administradores de sistemas sólo desean tener abierto un puerto de entrada publico, dedicado al Web.
En ese caso, podemos montar SPipe en el servidor web Apache de nuestra empresa, habilitando un nuevo puerto interno para recibir la conexión telnet que automáticamente vamos a cifrar con SSL y enviar al servidor web corporativo de nuestra delegación. Este servidor también tiene SPipe, por lo que va a descifrar el protocolo entrante, telnet en este caso, y va a enviarlo ya en plano al servidor telnet configurado.
De este modo, tenemos una sesión telnet sin necesidad de utilizar en los clientes certificado alguno.
El funcionamiento de dicha tubería se ve más claro en el siguiente gráfico:
Para que el servidor web de la empresa reciba la conexión telnet y no intente tratarla como http, o descifrarla, es necesario indicarle en el fichero de configuración que el protocolo entrante no utiliza SSL, lo que se hace poniendo en la sección correspondiente de su VirtualHost SSLSPipeInputNoSSL. No estaría de más aplicar a este VirtualHost una directiva AllowFrom para que solo desde las direcciones internas se permita esta conexión.
En el servidor Web de la delegación no debe aparecer esa directiva, pues él sí debe tratar el protocolo entrante como SSL, y descifrarlo. Pero sí que debe indicarse a dónde se desea redirigir, una vez descifrado, el protocolo entrante, en este caso a un servidor de telnet.
En este ejemplo se crea un canal seguro entre dos servidores telnet, pero se podrían encadenar cualquier número de servidores, indicando en los servidores intermedios que reenvíen con SSL lo que reciban. Para que esto funcionara la configuración de Apache sería la siguiente en el servidor web de la empresa:
<VirtualHost *:4443>
ServerAdmin
webmaster@dummy-host.example.com
DocumentRoot
/www/docs/dummy-host.example.com
ServerName
dummy-host.example.com
ErrorLog
logs/dummy-host.example.com-error_log
CustomLog
logs/dummy-host.example.com-access_log common
SSLEngine on
SSLCertificateFile
certs/server.crt
SSLCertificateKeyFile
certs/server.key
#This
directive is for showing headers
SSLSPipeShowHeaders
#This is to connect with
web server 2
SSLSPipeUrl
webserver2.dummy-host.remote.com:4443
#Client
does not use SSL
SSLSPipeInputNoSSL
#Timeout
SSLSPipeWait
1
</VirtualHost>
Mientras que en el servidor web de la delegación la configuración sería similar a la del ejemplo anterior, pero eliminando SSLSPipeInputNoSSL e indicando el servidor destino correspondiente en la directiva SSLSPipeUrl.
También se pueden realizar otras combinaciones diferentes, como un cliente que no hable SSL se conecte a un servidor web que codifique con SSL la entrada y lo reenvíe a un servidor que requiere SSL.
7.
Soluciones experimentales e ”Internals”
La clave en SPipe es poder distinguir el protocolo entrante en el servidor web, antes de decidir qué hacer con él. Esta distinción se realiza mediante la inspección del protocolo una vez descifrado el SSL.
Para distinguir si el
paquete es HTTP, utilizamos las directivas indicadas en el RFC 2616, es decir
OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE y CONNECT. En caso de que llegue
cualquiera de estas directivas se devuelve el control al núcleo de Apache y
sino se pasa al servidor indicado.
Pero este modo de funcionamiento, que permite inspeccionar el protocolo bajo el SSL, tiene la desventaja de que es aplicable sólo a protocolos que tomen la iniciativa de la conexión, siendo ellos los que envían los primeros bytes. Esto no es siempre así. Hay protocolos orientados a carácter en los que tras hacer el cliente el connect( ) de TCP, no se envía nada y se espera la respuesta del servidor antes de continuar. Esto implica que es imposible, para SPipe, conocer a qué servicio debe conectarse y redirigir el tráfico, pues no recibe byte alguno.
Servidores de este tipo son, por ejemplo, los servidores que utilizan protocolos de correo electrónico, SMTP (Simple Mail Transfer Protocol, RFC 821) y POP3 (Post Office Protocol versión 3, RFC 1939). Se ha elegido una solución que favorece la rapidez en la respuesta a una petición HTTP al servidor web. Para ello, se usa un parámetro configurable por Apache para esperar a que llegue un paquete por parte del cliente. Si dicho tiempo finaliza entonces se realiza la conexión al servidor remoto, y se continúa.
Como ya se ha indicado anteriormente, la solución de esperar el mensaje del cliente los segundos indicados se ha elegido para favorecer las peticiones HTTP, que no se verán afectadas pues HTTP siempre envía bytes, pero podría haber congestión en la red y el paquete HTTP del cliente puede retrasarse y en este caso nos conectaríamos al servidor configurado en vez de tratar la petición como una petición web. Por ello, en este caso, una vez conectados al servidor remoto, enviamos lo que nos llegue de éste al cliente, y entonces es el cliente el que tiene que enviar algo, sea el servidor que sea. Si la petición es HTTP y llega con retraso, se cierra limpiamente la conexión con el servidor remoto. Por lo tanto, no hay problemas introducidos por los retrasos.
Como se ve, es fundamental la espera que se realiza, y por ello ese intervalo de tiempo es configurable. De todos modos, para que este caso se diera debería producirse una gran tardanza (configurable) entre el connect( ) y la llegada de los tres o cuatro primeros bytes, y eso no suele ocurrir porque las implementaciones de TCP tienden a enviar juntos el mayor número posible de datos. Una tardanza elevada en este caso es un problema de comunicaciones, más que de la solución propuesta. En tal caso, este tipo de comunicaciones fallarían, del mismo modo que puede fallar la descarga de una página web si el servidor no responde en un tiempo adecuado.
Y en cualquier caso, esto es experimental, y OpenSource. “Si no te gusta, nadie te obliga a usarlo”.
http://www.apache.org : página del proyecto Apache.
http://www.mod_ssl.org : página de mod_ssl (OpenSSL para Apache).
http://www.openssl.org : página web de OpenSSL.
http://www.stunnel.org : página del paquete Stunnel.
A todo el grupo de desarrolladores de OpenSSL y mod_ssl por su constancia en el desarrollo de un producto sin el cual el software criptográfico no sería igual.
Al grupo de desarrollo de Apache, sin cuya aportación Internet sería más pequeña.
A la empresa Tool Banking Solutions (TBS) por permitir dedicar una pequeña parte de sus recursos a este pequeño proyecto.
Y en fin, a todos los que piensan que el único modo seguro de construir una Informática y un Internet para todos es mediante el uso y potenciación del OpenSource.