Sobre el autor :: Noticias :: Papers y publicaciones :: Exploits & Tools :: Proyectos :: Advisories :: Contribuciones

Proyectos


RewritingProxyTME - HTTP reverse proxy
08.Mar.2005

   Proyecto registrado en SourceForge, en Enero de 2005.

   RewritingProxyTME es un módulo Perl para Apache que provee la funcionalidad de "proxy inverso" con características avanzadas. Ha sido desarrollado en Telefónica Móviles España (TME), a partir de otro módulo incluido en el proyecto PAPI de RedIRIS, y se distribuye bajo licencia GNU (con permiso expreso de mis responsables en TME).

   Un proxy inverso se utiliza comúnmente para dar servicios web de forma segura, enmascarando y protegiendo a los servidores web reales. Para ello es situado en primera línea y atiende las peticiones HTTP / HTTPS del "exterior" (ej. Internet). Internamente mantiene una lista de "mapeos", que relacionan una o varias URLs del proxy (visibles externamente) con los servidores web "internos", de forma que cuando un usuario accede a una de estas URLs "mapeadas" el proxy primero contacta con el servidor web adecuado, para obtener la página pedida, y posteriormente devuelve el contenido al usuario. El proceso es totalmente transparente: el usuario no se entera de que hay uno o varios servidores web detrás del proxy inverso ni de los mapeos existentes; el único elemento visible es el propio proxy, el cual deberá estar correctamente securizado y actualizado, y que puede incluir funcionalidades adicionales como "caching" (guardar temporalmente las páginas en caché para poder servirlas directamente y así ahorrar tiempo y recursos en el servidor web), "IPS" (protección ante intrusiones), autenticación (sin tener que alterar el código de las aplicaciones web finales y de forma transparente lo que facilita la implantación de políticas de seguridad) o encriptación.

   Uno de los principales problemas que conlleva el uso de un proxy inverso es el alto número de incompatibilidades con las aplicaciones web. Por ejemplo, ¿qué ocurre si una página de una determinada aplicación contiene enlaces a la propia web usando URLs "absolutas" (ej: http://ip_web/algo)? Cuando el usuario haga clic en dichos enlaces el navegador intentará acceder directamente al servidor web final en vez de al proxy inverso. Como esto no será posible (habrá firewalls y/o problemas de routing que lo impedirán) el resultado es que el enlace está "roto" de cara al usuario y la navegación se verá interrumpida. El proxy inverso corrige este problema realizando un análisis del contenido que devuelve el servidor web y "traduciendo" URLs (por ejemplo, cambiando el hostname o IP del servidor web por el del proxy), antes de entregárselo al usuario. En realidad, este problema es mucho más complejo de lo que pueda parecer a primera vista y se acrecenta en los casos en los que las URLs de los enlaces se generan "al vuelo". Pensemos por ejemplo en un enlace generado en el lado del cliente a partir de código JavaScript. El proxy sólo vería sentencias JavaScript pero no una URL claramente identificable. ¿Cómo detectarlo entonces? Teóricamente se podría hacer si el proxy "entendiera" JavaScript; en la práctica, esto no suele ser así (ya sea porque complicaría en demasía la lógica del proxy o simplemente porque el rendimiento del mismo se pudiera ver afectado negativamente). Aún así, si conocemos la aplicación de antemano, podríamos programar el proxy para que reconociera un patrón de código JavaScript y lo sustituyera por otro de nuestra elección. Esto implica intervención manual (del administrador, programador o en definitiva la persona a cargo del proxy inverso) y además el proxy inverso debe ser lo suficientemente flexible como para permitir realizar reglas especiales de traducción.

   Otra de las problemáticas habituales es el tratamiento de cookies. Sin entrar en detalles, pongamos un único ejemplo: ¿qué ocurre si queremos integrar diferentes aplicaciones web que utilizan cookies con igual nombre (ej: "SESSION_ID") bajo el techo de un mismo proxy inverso? El navegador (i.e. el usuario) decide automáticamente que cookie enviar en las peticiones HTTP, dependiendo del hostname/ip del servidor al que está conectado, pero en este caso el proxy inverso es único, y habría un solapamiento de cookies correspondientes a diferentes servicios. ¿Cómo solucionarlo? Una vez más el proxy inverso debe soportar reglas especiales que permitan al administrador configurar una rápida "traducción de cookies" para cada aplicación.

   Los problemas discutidos son sólo una muestra de las dificultades que aparecerán sin duda al enfrentarnos a un proxy inverso. El desarrollo del módulo RewritingProxyTME se ha realizado con estos y otros muchos problemas similares en mente, y es resultado de mi experiencia al frente del diseño y administración de proxies inversos así como de la integración de diferentes y numerosas aplicaciones web con los mismos. Esta es la principal característica diferenciadora respecto a otras implementaciones de proxy inverso existentes.

   Resumimos a continuación las características más importantes de RewritingProxyTME:
  • Configuración de reglas de reescritura de URLs totalmente flexible. Se permite incluir un número indeterminado de reglas, usar expresiones regulares e incluso definir a qué tipo de contenido afectarán esas reglas (por defecto, afectan sólo a contenido HTML). Para esto último se pueden definir los MIME-Types que se verán afectados y/o patrones de URLs (basados también en expresiones regulares). Se ha añadido además la posibilidad de traducir datos que son enviados en las peticiones POST.
  • A su vez, la aplicación de las reglas de escritura se puede realizar en dos modalidades. Por defecto, se realiza una reescritura "inteligente", de forma que sólo se sobreescriben URLs en aquellos campos de los correspondientes tags HTML donde normalmente van los enlaces. Por si lo anterior falla (el parser HTML no es perfecto) existe una segunda modalidad (Raw_Redirect_All) que aplica las reglas sobre todo el documento, sin tener en cuenta el código y etiquetas HTML.
  • Todas las directivas de configuración se pueden incluir en la configuración Apache del vhost correspondiente, mediante "PerlSetVar" y/o "PerlAddVar". Así es posible personalizar cada vhost de forma rápida, sencilla y elegante.
  • Tratamiento avanzado de cookies.
  • Soporte HTTPS. Evidentemente también admite HTTP.
  • Es posible especificar un proxy HTTP a través del cual alcanzar el servidor web final, incluso aún siendo éste autenticado, resultando transparente al usuario.
  • Auto-relleno y posterior envío de formularios web. Si por ejemplo la aplicación final contiene una página de login basada en un formulario, podemos hacer que el proxy, al cargar la página, rellene automáticamente el formulario, lo envíe y muestre directamente la respuesta al usuario. De esta forma podemos integrar directamente en el proxy inverso webs finales que están autenticadas, pero que de cara al usuario no lo estarán. Se pueden incluir un número indeterminado de estas reglas de procesamiento de formularios.
  • Autenticación HTTP automática (tanto "Basic" como "Digest"). Al igual que en el caso anterior (formularios), el módulo puede responder automáticamente a peticiones de "HTTP Auth", de forma transparente al usuario.
  • El módulo añade bastantes líneas de "debug" (desactivadas por defecto), de forma que en caso de dificultades cuando se está integrando una web nos puedan dar pistas acerca de cómo resolver el problema y orientar al integrador.

   RewritingProxyTME ha sido probado con éxito en entornos de producción basados en Apache 1.3.x y Mod_Perl 1.x. Animo a todos a que lo probeis, no sin antes haberos leído la documentación incluida, y por supuesto estoy abierto a sugerencias y posibles colaboraciones que impulsen el presente proyecto. Debido a limitaciones de tiempo no atenderé a consultas que no estén estrictamente relacionadas con el módulo. En especial, las referentes a instalación y configuración de Apache y/o Mod_Perl serán ignoradas (en caso de duda se aconseja consultar la documentación oficial de Apache y/o Mod_Perl).


Descargar   RewritingProxyTME-0.7.tar.gz  (201 KB)