Loading...

Seguridad · 7 min de lectura

HSTS: enseña al navegador a no hablarle nunca en HTTP a tu sitio

Tienes un certificado, rediriges HTTP a HTTPS y el candado está ahí. Aun así queda una petición que un visitante hace en texto plano — la primera — y es exactamente la que espera un atacante en la misma red. HSTS la cierra: una sola cabecera de respuesta que hace que el navegador se niegue a usar HTTP con tu dominio, durante el tiempo que tú decidas. Esta guía explica la cabecera, qué compromiso adquieres realmente con cada uno de sus tres ajustes, y cómo activarla y verificarla en cdn.com.tr sin dejarte fuera.

Actualizado

HSTS: enseña al navegador a no hablarle nunca en HTTP a tu sitio

La petición que tu redirección nunca ve

Casi todo sitio con certificado hace lo mismo: responder en el puerto 80 con un 301 hacia la dirección https://. Eso es correcto, y debes mantenerlo. Solo que llega una petición tarde.

Cuando alguien escribe example.com en la barra de direcciones, sigue un enlace de un correo antiguo o abre un marcador de hace años, el navegador no tiene motivo para asumir HTTPS. Abre una conexión HTTP en claro y pide la página. Tu redirección responde — pero la pregunta ya se envió sin cifrar, por la red que sea que esté usando el visitante: una cafetería, un aeropuerto, un hotel, un portal cautivo, un router doméstico que nadie ha actualizado.

Cualquiera en posición de leer esa petición también está en posición de responderla. En lugar de dejar pasar tu 301, sirve su propia copia de tu sitio por HTTP y hace de proxy silenciosamente hacia ti por HTTPS. El visitante ve una página que parece correcta, salvo por un candado que casi nadie comprueba, y escribe su contraseña en ella. Esto se llama SSL stripping, y es un ataque de downgrade dirigido justo a la petición que tu redirección existe para arreglar.

HSTS elimina esa petición del mundo. En cuanto el navegador ha visto la cabecera, reescribe http://example.com/... a https://... internamente, antes de que nada salga del dispositivo. No hay petición en claro que interceptar, ni advertencia de certificado que el visitante pueda saltarse con un clic.

Lo que dice la cabecera

Strict-Transport-Security: max-age=31536000 es, en la práctica, todo lo que necesitas. Puede llevar tres ajustes, y el compromiso que adquieres con cada uno es muy distinto.

max-age es el único obligatorio: cuántos segundos debe recordar el navegador que este host es solo-HTTPS. 31536000 es un año. El reloj se reinicia en cada respuesta, así que un sitio visitado activamente mantiene siempre un año por delante, mientras que uno que nadie visita acaba olvidándolo.

includeSubDomains extiende la regla a todo nombre bajo el tuyo — www, api, shop, staging, y ese del que te olvidaste. Es genuinamente más fuerte, porque una cookie fijada en un dominio padre se puede atacar a través de cualquier subdominio suyo. También es el ajuste que rompe cosas, porque se aplica a hosts que quizá no controlas y para los que quizá no tienes certificado.

preload pide que tu dominio se compile dentro de los propios navegadores, de modo que solo-HTTPS se aplique antes incluso de que un visitante haya estado nunca en tu sitio. Requiere includeSubDomains y un max-age largo, y es muy difícil de revertir.

Una regla subyace a las tres: la cabecera solo cuenta en una respuesta HTTPS. Los navegadores la ignoran deliberadamente en HTTP puro, porque respetarla ahí permitiría a cualquiera en la red fijar un dominio que no le pertenece.

Por qué enviamos solo max-age

El preset de cdn.com.tr envía max-age=31536000 y nada más. Es un valor por defecto deliberado, no una limitación, y merece la pena entender a qué te comprometerían los otros dos ajustes.

includeSubDomains alcanza nombres que no tienes delante en la página donde lo activaste: un host mail. heredado en un servidor antiguo, una página status., una herramienta interna en un subdominio que lleva años respondiendo en HTTP puro. En cuanto un navegador tiene la regla, cada uno de ellos se vuelve inalcanzable en ese navegador — no una advertencia, un fallo total — y quitar la cabecera no lo arregla, porque el navegador ya anotó la regla.

preload falla en la misma dirección, solo que más despacio: retirarlo exige una solicitud a una lista de terceros y esperar a que las versiones del navegador se publiquen, algo que se mide en meses.

Un max-age de un año en el hostname que realmente sirves te da todo el beneficio de seguridad para ese hostname desde la primera visita. Los ajustes más fuertes merece la pena añadirlos más adelante, deliberadamente, una vez que cada nombre bajo tu dominio esté inventariado y migrado a HTTPS. Empieza por donde puedes estar seguro, no por donde luego puedas arrepentirte.

La lista de comprobación antes de activarlo

HSTS no es arriesgado. Activarlo en un sitio que no está listo, sí lo es. Repasa esto primero.

Toda página carga por HTTPS. No solo la página de inicio: el área de administración, la API, los endpoints de subida, los destinos de webhooks, URLs de campañas antiguas. Cualquier cosa que solo funcione en el puerto 80 deja de funcionar para todo aquel que haya visto la cabecera.

El certificado es válido y se renueva solo. Bajo HSTS, un certificado caducado ya no es una advertencia que el visitante pueda ignorar — es un muro. Los certificados de cdn.com.tr se emiten y renuevan automáticamente, que es exactamente la propiedad que HSTS asume que tienes.

No queda contenido mixto. Scripts, hojas de estilo, imágenes e iframes referenciados con http:// deberían estar ya corregidos; HSTS solo hace más ruidoso su fallo.

Sabes qué hacen tus subdominios. No porque vayas a activar includeSubDomains hoy, sino porque querrás hacerlo eventualmente, y el inventario es el trabajo de verdad.

Tu redirección de HTTP a HTTPS sigue en su sitio. HSTS protege a los navegadores que ya han visto la cabecera; la redirección atrapa a todos los demás. No son alternativas entre sí.

Activarlo

En el panel, abre Reglas de entrega → Presets de seguridad. El campo "Ajuste de seguridad" es un multiselect de los presets de edge que se aplican a la cuenta: elige Hsts y guarda. La página está en /management/cdn/advanced-management.

El ajuste es por cuenta, así que un hostname que todavía no está listo simplemente puede esperar en una cuenta propia, en lugar de retrasar a los que sí lo están.

Una vez guardado, el edge añade la cabecera a las respuestas HTTPS de esa cuenta, y solo a las respuestas HTTPS — una petición HTTP en claro sigue recibiendo tu redirección, sin ninguna cabecera adjunta, que es el comportamiento que exige la especificación. Nada cambia en tu origen: no hay cabecera que añadir en nginx, Apache o tu framework, porque el edge es donde se decide la respuesta que ve el visitante.

Verificarlo en diez segundos

Pide las cabeceras y busca esa única línea. Importan dos resultados, y el segundo es el que la gente se salta.

La cabecera pertenece a las respuestas HTTPS y a ningún otro sitio

# debería imprimir: strict-transport-security: max-age=31536000
curl -sI https://example.com/ | grep -i strict-transport

# no debería imprimir nada
curl -sI http://example.com/ | grep -i strict-transport

Lo que recuerda el navegador

La línea de comandos te dice qué estás enviando. El navegador es donde la cabecera realmente hace su trabajo, y merece la pena confirmar una vez que la regla se ha asentado.

Visita el sitio por HTTPS, luego abre una pestaña nueva y escribe el hostname a secas. La barra de direcciones debería saltar directamente a https:// — la reescritura ocurre dentro del navegador, así que no hay petición en el cable que interceptar ni redirección que seguir. Chrome expone lo que tiene almacenado en chrome://net-internals/#hsts, incluida la caducidad, lo cual es útil cuando estás probando en lugar de adivinando.

Dos hábitos evitan confusiones aquí. Prueba desde un perfil de navegador que nunca haya visitado el sitio cuando quieras ver el comportamiento de primera visita, y recuerda que un navegador que aprendió la regla antes de que cambiaras nada seguirá actuando según ella — que es justo el tema de la siguiente sección.

Revertirlo, y lo que la reversión no puede hacer

Desmarca Hsts en el mismo multiselect y guarda. El edge deja de enviar la cabecera de inmediato, y cualquier navegador que nunca la haya visto se comporta con normalidad desde entonces.

Lo que no ocurre es la parte que sorprende a la gente: los navegadores que ya registraron la regla la siguen haciendo cumplir hasta que su max-age se agota. Desactivar el preset no llega hasta ellos. Con un max-age de un año, un visitante que vio la cabecera ayer seguirá forzando HTTPS durante un año, diga lo que diga tu servidor ahora.

La especificación sí prevé una retirada progresiva para ese caso — servir la cabecera con max-age=0 le dice a un navegador que olvide la regla la próxima vez que visite por HTTPS. Solo funciona mientras el sitio siga siendo accesible por HTTPS, y hay que seguir enviándola hasta que los navegadores que te importan hayan vuelto, así que es una retirada planificada, no un interruptor.

Por eso la lista de comprobación importa más que el plan de reversión. El fallo realista nunca es "HSTS fue un error para nosotros"; es "una sola URL solo funcionaba por HTTP y lo descubrimos después". Arreglar esa URL es casi siempre el camino de vuelta más rápido.

Dónde encaja HSTS entre tus otras protecciones

HSTS hace exactamente una cosa: elimina la petición en texto plano. Merece la pena tenerlo claro, porque a veces se dice "tenemos HSTS" como si con eso ya estuviera resuelta la cuestión de seguridad.

No es un certificado — asume que hay uno válido y hace que uno inválido sea fatal. No es cifrado; eso lo hace TLS, y HSTS solo garantiza que se use TLS. No inspecciona nada, así que no detiene ninguna inyección, ningún exploit ni ninguna carga maliciosa: de eso se encarga un WAF. No cuenta nada, así que la fuerza bruta y el scraping siguen siendo trabajo del rate limiting. Y no dice nada sobre quién puede llegar hasta ti, que es donde entra el bloqueo por país y ASN.

Lo que hace que merezca cinco minutos es la proporción. Una cabecera, un ajuste, sin mantenimiento continuo — y toda una clase de ataque de downgrade deja de ser posible contra tus visitantes.

Preguntas frecuentes

¿Basta HSTS por sí solo?

No, y no está pensado para eso. HSTS garantiza que la conexión está cifrada; no dice nada sobre lo que viaja por ella. Una petición que lleva una inyección SQL llega igual de tranquila por HTTPS que por HTTP. Va junto a un certificado válido, un WAF, rate limiting y reglas de acceso sensatas — no en lugar de ellos.

¿HSTS sustituye a mi redirección de HTTP a HTTPS?

No. Mantén la redirección. HSTS solo se aplica después de que un navegador haya visto la cabecera al menos una vez por HTTPS, así que cada visitante por primera vez, cada dispositivo nuevo y cada rastreador siguen llegando por el puerto 80 y necesitan el 301. Los dos cubren mitades distintas del mismo problema.

¿Cubre mis subdominios?

No con este preset. Envía solo max-age, así que la regla se aplica exactamente al hostname que sirvió la respuesta. Cubrir subdominios exige includeSubDomains, que es un compromiso mucho mayor: surte efecto en el navegador de inmediato y no se puede retirar desde ahí, así que cada nombre bajo tu dominio tiene que funcionar sobre HTTPS antes de planteártelo.

¿Debería enviar mi dominio a la lista de precarga de HSTS?

Solo después de que HTTPS en todas partes haya sido aburrido durante meses. La precarga mete tu dominio dentro del navegador, así que protege incluso la primerísima petición de un visitante — pero retirarlo implica una solicitud a un tercero y una espera a que salgan versiones del navegador, así que un error dura mucho tiempo. Un max-age de un año te da la mayor parte del beneficio y mantiene un camino de vuelta.

¿HSTS protege la primerísima visita de alguien?

Por sí solo, no — ese es el único hueco que deja. La primera visita es la que enseña la regla al navegador, y está protegida por tu redirección y un certificado válido, no por HSTS. La precarga es la única forma de cerrar ese hueco, y por eso existe la lista.

¿Afectará al rendimiento?

Ligeramente a tu favor. La cabecera son unas pocas docenas de bytes, y en cuanto el navegador la tiene, cada enlace http:// a tu sitio se reescribe dentro del navegador en lugar de costar un viaje de ida y vuelta a tu redirección. Los visitantes que antes llegaban a través de un 301 se lo ahorran por completo.