HTTPs 302
Es posible hacer una redirección del protocolo HTTPs a HTTP?. Respuesta corta: NO y Respuesta larga: NO... pero hay un "escenario" que hoy intentaremos explicar. Pero, primero, veamos qué sucede cuando se establece una conexión HTTPs:
- El navegador del cliente intenta conectarse a una URL que usa HTTPs (puerto 443 por defecto).
- El cliente y el servidor inician un handshake TLS (una negociación para establecer un canal cifrado).
- Durante ese proceso, el servidor donde está alojada la URL envía un certificado digital, que el navegador del cliente valida para verificar que está hablando con el sitio correcto (por ejemplo, que el certificado sea válido para https://www.example.com).
- Solo si ese proceso es exitoso, se establece una conexión segura y recién ahí se transmiten los datos reales.
En realidad suceden más cosas, pero para qué alargar el asunto. Aquí lo importante es que todo está cifrado desde el principio y no hay manera de ver ni modificar el contenido.
Escenario
¿Y qué sucedería si tenemos una una red LAN centralizada y administrada por un servidor o router, actuando como Man-in-the-Middle MITM, y queremos bloquear https://www.facebook.com e inyectarle una redirección a una página de bloqueo personalizada?
- El navegador solicita el certificado SSL de facebook.
- El servidor de facebook responde con su certificado.
- Aquí, el MITM interviene e inyecta una redirección de facebook hacia nuestra página de bloqueo.
- El navegador espera recibir el certificado legítimo de facebook y en su lugar recibe algo diferente y se rompe la conexión SSL y la página "se cae" con un mensaje de error similar al siguiente:
Esta es precisamente la razón por la cual no se pueden mostrar mensajes de advertencia, bloqueos u otro tipo de contenido personalizado cuando se trata del protocolo HTTPs.
A Long, Long Time Ago...
Antes de 2010, cuando aún no se había adoptado de forma masiva el protocolo HTTPs, la mayoría de los sitios en Internet utilizaban HTTP. En ese contexto, por ejemplo, con un proxy como Squid-Cache operando en una LAN centralizada, bastaba con definir una regla de bloqueo y agregar la cláusula deny_info para mostrar al cliente una página de error personalizada. Sin embargo, con la transición a HTTPs, esta cláusula ha perdido efectividad (solo sirve para HTTP), pero, existe otra alternativa.
Tomando nuevamente como ejemplo a Squid-Cache, este proxy ofrece la directiva SSL-Bump, que permite interceptar la conexión HTTPs, generar en tiempo real un certificado falso y entregárselo al cliente, actuando como intermediario MITM. Esto permitiría redirigir o bloquear el acceso mostrando mensajes personalizados, pero el navegador lanza una alerta:
![]() |
Alerta en el navegador por certificado SSL personalizado |
Como podemos observar, en la práctica, esta solución es casi inviable, debido a la gran diversidad de sistemas operativos y navegadores, así como a las crecientes restricciones de seguridad que dificultan la instalación y confianza en un certificado raíz personalizado en cada dispositivo, y, lo más importante, que este tipo de manipulación del tráfico puede violar políticas de privacidad o regulaciones legales, dependiendo del contexto y la jurisdicción.
Otras alternativas muy populares y menos invasivas son soluciones como Pi-hole y OpenDNS, que operan a nivel de resolución de nombres de dominio (DNS). Estas herramientas filtran las solicitudes, bloqueando dominios conocidos por alojar publicidad, rastreadores, malware, contenido no deseado, etc. Pi-hole suele implementarse en redes LAN como un servidor DNS interno, mientras que OpenDNS ofrece un servicio similar desde la nube. No obstante, este enfoque vuelve la navegación lenta a medida que las listas de bloqueo crecen en tamaño y cantidad de líneas de dominios a bloquear, y no permite inspeccionar el contenido de las conexiones cifradas ni mucho menos realizar redirecciones a páginas personalizadas, ya que hacerlo requeriría romper el cifrado SSL, algo para lo cual no están diseñadas (OpenDNS tiene un certificado, pero ocurriría el mismo problema que con SSL-Bump).
En este punto ya deberíamos saber que la respuesta simple, como mencionamos al principio, es: No se puede redireccionar HTTPs a nuestro antojo. Pero esto no significa que nos quedemos cruzados de brazos. A continuación una solución a nuestro "escenario".
Principio de los portales cautivos
Antes de entrar en materia, primero hay que conocer el funcionamiento básico de los portales cautivos (hotspot). Un portal cautivo no intercepta el tráfico HTTPs (y por tanto no viola ninguna regulación). Lo que hace es evitar que el cliente navegue libremente hasta que pase por una página de autenticación o aviso.
Cuando un cliente se conecta por primera vez a la red (ya sea cableada, Wi-Fi pública, etc.), el sistema bloquea todo el tráfico saliente, excepto algunas excepciones mínimas, como DNS y HTTP. Si el cliente intenta abrir cualquier sitio web, se produce algo conocido en el argot popular como "connectivity check" (también recibe otros nombres más técnicos, como "captive portal detection", etc.).
Este "connectivity check", en el contexto de sistemas operativos y navegadores, es un mecanismo mediante el cual el dispositivo verifica si tiene acceso real a Internet y consiste en hacer una petición HTTP a una URL conocida, normalmente a un servidor controlado por el fabricante del sistema (como Google, Microsoft o Apple). Por ejemplo, al conectarse a una red, el sistema operativo o navegador puede hacer una solicitud a una URL específica, como:
- http://clients3.google.com/generate_204 (Android/Chrome)
- http://www.msftconnecttest.com/connecttest.txt (Windows)
- http://captive.apple.com (Apple)
- http://detectportal.firefox.com/success.txt (Firefox)
Si la respuesta es la esperada, por ejemplo, un código "HTTP 204 No Content" o un texto específico, el sistema concluye que hay conectividad a Internet.
Y sucede la magia
Estas peticiones de verificación no van por HTTPs, sino por HTTP, lo que significa que pueden ser interceptadas y redireccionadas automáticamente al portal cautivo y responde con una redirección HTTP 302.
Dicho de otro modo, no se redirige la petición HTTPs propiamente, sino que se espera a que el cliente active el mecanismo de verificación, que es por HTTP, y se intercepta para guiarlo al portal.
Y ¿cómo aplicamos estas técnicas en nuestro "escenario"?
Una vez entendido estos principios, lo siguiente es montar una página que muestre el aviso al cliente y configurarla para que sea servida tanto por HTTP como por HTTPs; aunque este último, como ya vimos, solo tendrá efecto si el cliente la abre directamente, ya que no hay redirección HTTPs. Para esto usaremos un servidor Linux, con apache2, iptables e ipset y... nada más.
Paso 1: Crear una página HTML
Primero creamos una página simple en HTML que será la advertencia o mensaje de restricción que verá el cliente. Luego, la alojamos en Apache2 (o en cualquier otro servidor HTTP que prefieran). A continuación un ejemplo (puede modificarla a su gusto):
#!/bin/bash mkdir -p /var/www/html/warning chown -R www-data:www-data /var/www/html/warning tee /var/www/html/warning/warning.html >/dev/null << EOL <!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Acceso restringido | Restricted Access</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { background: #f2f5f8; font-family: "Segoe UI", Tahoma, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; } .container { background: white; padding: 40px; border-radius: 10px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); text-align: center; max-width: 400px; width: 90%; } .container img { width: 80px; margin-bottom: 20px; } h1 { color: #333; margin-bottom: 10px; } p { color: #666; margin-bottom: 30px; } .quota { text-align: left; background: #f9fafc; border: 1px solid #ddd; padding: 15px; border-radius: 6px; font-size: 14px; } .quota li { margin-bottom: 8px; } .footer { font-size: 12px; color: #aaa; margin-top: 30px; } </style> </head> <body> <div class="container"> <svg width="80" height="80" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> <path d="M50 10 L90 80 L10 80 Z" fill="none" stroke="#e53e3e" stroke-width="6" stroke-linejoin="round"/> <circle cx="50" cy="65" r="3" fill="#000"/> <line x1="50" y1="30" x2="50" y2="55" stroke="#000" stroke-width="6" stroke-linecap="round"/> </svg> <h1>Acceso restringido<br> Restricted Access</h1> </div> </body> </html> EOL
Paso 2: Configurar Apache para HTTP y HTTPs
Ahora creamos dos VirtualHost en Apache2, uno que escuche en el puerto 18880 (HTTP) y otro en 18443 (HTTPs), ambos mostrando la misma página de advertencia (puede usar los puertos y path de su preferencia):
#!/bin/bash # defina la dirección IP del servidor server_ip="192.168.0.10" tee /etc/apache2/sites-available/warning.conf >/dev/null << EOL <VirtualHost *:18880> ServerAdmin webmaster@localhost DocumentRoot /var/www/html/warning <Directory /var/www/html/warning> DirectoryIndex warning.html Options -Indexes +FollowSymLinks AllowOverride None Require all granted </Directory> RewriteEngine On RewriteCond %{REQUEST_URI} !^/warning\.html$ RewriteCond %{HTTP_HOST} !^${server_ip//./\\.}$ RewriteRule ^.*$ http://${server_ip}:18880/warning.html [R=302,L] ErrorLog ${APACHE_LOG_DIR}/warning_error.log CustomLog ${APACHE_LOG_DIR}/warning_access.log combined </VirtualHost> EOL chmod 644 /etc/apache2/sites-available/warning.conf touch /var/log/apache2/{warning_access,warning_error}.log tee /etc/apache2/sites-available/warning-ssl.conf >/dev/null << EOL <VirtualHost *:18443> ServerAdmin webmaster@localhost DocumentRoot /var/www/html/warning SSLEngine on SSLCertificateFile /etc/ssl/certs/warning/cert.pem SSLCertificateKeyFile /etc/ssl/private/warning/key.pem <Directory /var/www/html/warning> DirectoryIndex warning.html Options -Indexes +FollowSymLinks AllowOverride None Require all granted </Directory> RewriteEngine On RewriteCond %{REQUEST_URI} !^/warning\.html$ RewriteRule ^.*$ /warning.html [R=302,L] ErrorLog ${APACHE_LOG_DIR}/warning_ssl_error.log CustomLog ${APACHE_LOG_DIR}/warning_ssl_access.log combined </VirtualHost> EOL chmod 644 /etc/apache2/sites-available/warning-ssl.conf touch /var/log/apache2/{warning_ssl_access,warning_ssl_error}.log
Paso 3: Habilitar los puertos, certificado y módulos necesarios
Ahora levantamos los puertos a escuchar en
ports.conf
si no están ya definidos:#!/bin/bash server_ip="192.168.0.10" grep -q 'Listen 0.0.0.0:18880' /etc/apache2/ports.conf || echo 'Listen 0.0.0.0:18880' >> /etc/apache2/ports.conf grep -q 'Listen 0.0.0.0:18443' /etc/apache2/ports.conf || echo 'Listen 0.0.0.0:18443' >> /etc/apache2/ports.conf mkdir -p /etc/ssl/private/warning /etc/ssl/certs/warning openssl req -x509 -nodes -newkey rsa:2048 -days 365 \ -keyout /etc/ssl/private/warning/key.pem \ -out /etc/ssl/certs/warning/cert.pem \ -subj "/C=CO/ST=Some-State/L=City/O=CaptivePortal/CN=${$server_ip}" >/dev/null 2>&1 a2ensite -q warning.conf a2ensite -q warning-ssl.conf a2enmod ssl a2enmod rewrite update-ca-certificates -f systemctl daemon-reload systemctl restart apache2
Paso final: redirección y bloqueo con iptables + ipset
Una vez tengamos lista y funcionando la página que le vamos a mostrar al cliente, pasamos a configurar la redirección con ipset/iptables . Ejemplo:
#!/bin/bash # definimos la interfaz de red LAN lan=eth1 # definimos la dirección IP del servidor man-in-the-middle server_ip="192.168.0.10" # Limpieza de reglas previas iptables -F iptables -X iptables -t nat -F iptables -t nat -X iptables -Z ip6tables -F ip6tables -X ip6tables -P INPUT DROP ip6tables -P OUTPUT DROP ip6tables -P FORWARD DROP # Desactivar IPv6 sysctl -q -w net.ipv6.conf.all.disable_ipv6=1 sysctl -q -w net.ipv6.conf.default.disable_ipv6=1 sysctl -q -w net.ipv6.conf."lan".disable_ipv6=1 # Políticas base iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT echo 1 > /proc/sys/net/ipv4/ip_forward # Crear ipset si no existe ipset -L banclients >/dev/null 2>&1 if [ ? -ne 0 ]; then ipset -! create banclients hash:net family inet hashsize 1024 maxelem 65536 else ipset -! flush banclients fi ipset add banclients $server_ip ### REDIRECCIÓN HTTP (Puerto 80 al portal) iptables -t nat -A PREROUTING -i $lan -m set --match-set banclients src -p tcp --dport 80 -j DNAT --to $server_ip:18880 iptables -A INPUT -i $lan -m set --match-set banclients src -p tcp --dport 18880 -j ACCEPT # RECHAZAR HTTPs con reset (activa connectivity check) iptables -A INPUT -i $lan -p tcp --dport 18443 -j ACCEPT iptables -t nat -A PREROUTING -i $lan -m set --match-set banclients src -p tcp --dport 18443 -j DNAT --to-destination $server_ip:18443 ### BLOQUEO GENERAL PARA TODO LO DEMÁS iptables -A FORWARD -i $lan -m set --match-set banclients src -j DROP iptables -A INPUT -i $lan -m set --match-set banclients src -j DROP echo "Clientes en banclients solo verán HTTP y serán bloqueados en todo lo demás"
Como vimos, no es posible redirigir directamente el tráfico HTTPs, debido a la naturaleza cifrada del protocolo, sin embargo, mediante el uso de técnicas similares a las empleadas por los portales cautivos, podemos abusar aprovecharnos de mecanismos como el llamado "connectivity check" para mostrar advertencias o requisitos de acceso —ya sea un login, un aviso de términos, un formulario, página de bloqueo, etc.— antes de permitir la navegación completa.
Con unas pocas herramientas del kernel de Linux —como iptables, ipset y un servidor web básico— es posible implementar un sistema funcional que:
- Detecta clientes (no autenticados o bloqueados por el administrador).
- Los redirige a una página HTTP (de login, aceptación de términos, restricciones de acceso a URLs, etc.)
- Bloquea todo el tráfico restante hasta que se cumpla la condición definida por el administrador de sistemas o la empresa.
Esta solución, aunque no perfecta, sigue siendo una de las estrategias más efectivas y viables para controlar el acceso a redes locales, especialmente en entornos públicos o semi-controlados.
Si quiere ver este proceso en acción, visite el proyecto LightSquid, donde implementamos esta técnica bajo el nombre bandata.
Si quiere ver este proceso en acción, visite el proyecto LightSquid, donde implementamos esta técnica bajo el nombre bandata.
Post a Comment