HSTS en Spring Security y por qué deberías de conocerlo

Introducción

El uso de librerías y marcos de trabajo terceros, si bien facilitan el trabajo por las abstracciones que proveen, conllevan como tal un cierto nivel de riesgo. El riesgo puede ser manifestado como tener que modificar parte del código en nuevas versiones del marco de trabajo, que deje de existir o dar soporte u opciones por defecto que pueden causar efectos secundarios. De lo que les escribiré en este artículo es de esto último, una opción por defecto que tiene habilitada el marco de trabajo de Spring Security a partir de la versión 3.2.0 la cual, al usarla en conjunto con “click tracking” (rastreo de clics) en los correos electrónicos puede causar un problema. Esta opción por defecto es el encabezado de HSTS.

Sobre HSTS

Antes de ahondar en el problema, describamos primero qué es HSTS. Las siglas significan HTTP Strict Transport Security, en resumen es un mecanismo de seguridad de HTTP que indica a los clientes que deben de usar forzosamente el protocolo seguro de HTTP (HTTPS) al conectarse a un determinado dominio. Este protocolo es implementado por medio de un encabezado HTTP que es enviado desde el servidor al cliente (navegador web):

Strict-Transport-Security: max-age=31536000

El encabezado es interpretado por el navegador como una instrucción de registrar el dominio en una lista para que a la próxima vez que el usuario teclee el dominio, anteponga el propio navegador el prefijo “https://” en lugar de “http://”. Este encabezado debe de proporcionar un tiempo de “expiración” en segundos. En el ejemplo anterior, la expiración es de 1 año.

Lo anterior es bueno en el sentido que aseguramos desde el cliente que se esté usando un protocolo seguro.

Adicionalmente puede tener de forma opcional la instrucción “includeSubDomains”. Esta opción indica que todos los subdominios también deben de tener “https://”. El encabezado con esta opción habilitada queda de la siguiente manera:

Strict-Transport-Security: max-age=31536000; includeSubDomains

En Chrome pueden consultar y editar las configuraciones de HSTS en la siguiente URL: chrome://net-internals/#hsts

Encabezados de Spring Security por defecto

Al incluir Spring Security en el proyecto se agregan por defecto varios encabezados. En la documentación se detallan cuáles son:

https://docs.spring.io/spring-security/site/docs/current/reference/html/headers.html

Como pueden ver Spring Security pone por defecto el siguiente encabezado de HSTS:

Strict-Transport-Security: max-age=31536000 ; includeSubDomains

De acuerdo a la explicación de la sección anterior, este encabezado dará la instrucción al navegador web de poner el prefijo “https://” en todas las URLs del dominio, incluyendo los subdominios.

Click tracking en correos

Los servicios de envío de correo electrónico como Mailgun (https://www.mailgun.com/), ofrecen una funcionalidad denominada “click tracking” (rastreo de clics). En caso de enviar correos electrónicos en donde existan hipervínculos, esta funcionalidad permite rastrear en qué hipervínculo hizo clic la persona que abrió el correo electrónico. Esto resulta útil para realizar un análisis sobre la efectividad de los correos enviados. En Mailgun esta funcionalidad es implementada por medio de una reescritura de los links a un subdominio que es vinculado a Mailgun y luego es redirigido a la URL real.

Explico esto último: Al registrar un dominio en Mailgun, se pide agregar una serie de valores al DNS del dominio para demostrar que somos propietarios del mismo y ligarlo con el servicio. Entre todos los registros a agregar se nos pide opcionalmente crear un subdominio para la funcionalidad de “click tracking”:

La anterior configuración del DNS hará que las peticiones a “email.dominio.com” se traduzcan a “mailgun.com”.

Al habilitar “click tracking” lo que hará Mailgun es reescribir los todos los hipervínculos de los correos a “http://email.dominio.com/c/{identificador}” donde {identificador} es un identificador de Mailgun que está ligado con el correo enviado y la URL original que sustituyó. Lo que sucede al dar clic en el hipervínculo es:

  1. La petición es reescrita por el DNS a “mailgun.org/c/{identificador}”.

  2. Mailgun usa el identificador para obtener la información del correo, esencialmente a quién fue dirigido.

  3. Mailgun registra esta información en la bitácora.

  4. Mailgun redirige a la URL original.

Escenario problema

Quienes hasta ahora estén atentos, notarán que existe un escenario en donde la combinación de “Click tracking” con HSTS configurado como está por defecto en Spring Security, causará que los links en los correos se rompan.

Les detallo a continuación este escenario:

  1. El usuario entra a dominio.com

  2. Spring Security envía el encabezado:

    1. Strict-Transport-Security: max-age=31536000 ; includeSubDomains

  3. HSTS es instalado en el navegador web para dominio.com y sus subdominios.

  4. El sistema en dominio.com envía a través de Mailgun un correo con un hipervínculo a dominio.com (ej. https://dominio.com/user/3)

  5. El usuario abre el correo.

  6. El hipervínculo es mostrado con la reescritura como http://email.dominio.com/c/ie7y3238hd239dh

  7. El usuario hace clic en el hipervínculo.

  8. El navegador, por HSTS, reescribe la URL a https://email.dominio.com/c/ie7y3238hd239dh

  9. El DNS traduce la petición como https://mailgun.org/c/ie7y3238hd239dh

  10. BOOM!

¿Qué sucede? Al final queremos conectarnos a la IP a donde resuelve mailgun.org usando el puerto 443, sin embargo el servidor de esa IP obviamente no tiene el certificado con el subdominio email.dominio.com. Es más, la instancia con la IP a donde resuelve mailgun.org tiene el puerto 443 cerrado. De forma práctica la persona verá un error de “time-out” en su navegador web, haciendo inservible el hipervínculo.

Lo que hace interesante este escenario es que si el usuario hubiese hecho clic en el hipervínculo del correo antes, todo habría funcionado correctamente, ya que el encabezado de HSTS no habría estado instalado en su navegador web.

Soluciones

Habiendo explicado el escenario problema, existen dos formas de resolverlo:

Como buena práctica está el proporcionar textualmente (“en crudo”) cada hipervínculo al usuario para que, en caso de cualquier problema, pueda copiarlo y pegarlo en la barra de direcciones.

Cabe mencionar que este mismo escenario sucede en SendGrid, ellos ofrecen un workaround: https://sendgrid.com/docs/Classroom/Track/Clicks/clicktracking_ssl.html

Conclusión

Lo que muestro aquí es sólo un escenario en donde uno de los encabezados incluidos por defecto en Spring Security puede causar un problema al usarlo en conjunto con otro servicio. Como es posible ver en la documentación de Spring Security, existen otros encabezados que pueden causar otros efectos secundarios, tal como “Cache-Control: no-cache, no-store” (no guardar caché en el navegador). Por supuesto, todos ellos tienen una razón de ser y son explicados muy bien en este blog post del equipo de Spring: https://spring.io/blog/2013/08/23/spring-security-3-2-0-rc1-highlights-security-headers/. En marcos de trabajo o librerías que cubren de forma ortogonal el proyecto es importante, en la medida de lo posible, conocer sus configuraciones por defecto y determinar si alguna de ellas puede causar algún efecto en otra parte del proyecto.

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de Nopalin

Yo considero que estas

Yo considero que estas haciendo una tormenta en un vaso de agua jajaja. Si todo es HTTPS, indicale a tu proveedor que escuche por ese puerto el click tracking y listo.

Saludos

No es así de trivial como lo

No es así de trivial como lo pones por dos razones:

1.- El servidor a donde resuelve el dominio target del CNAME (mailgun.org en este caso) necesita tener instalado el certificado con el subdominio email.dominio.com incluido. Aparte, claro, debe tener el puerto 443 abierto. Lo del certificado es básico para que funcione HTTPS.

2.- Hay varias formas de resolver esto por parte del proveedor pero involucra que cambie sus funcionalidades y/o infraestructura. En particular con Mailgun hay un ticket del 2014 que sigue abierto pidiendo una solución para sitios con HSTS https://mailgun.uservoice.com/forums/156243-general/suggestions/6529938-....

Imagen de Nopalin

Es que asi como lo pones

Es que asi como lo pones indicas que es un problema de el header que asigna spring security y no, es problema del proveedor de correos, ya que estarías en la misma situación si envias una URL con https.

Ahora, si me queda claro el error, ya que te estaras conectando al servidor de mailgun.org pero pasándole un host de mail.subdominio.com y ps no coincidirá. Aquí la pregunta del millon de dolares, quien hizo el diseño tan feo de tener un subdominio tuyo que se resuelva a una IP de ellos? por que no directamente que la URL en el correo se reescriba a mailgun.org? ¿Cual es la ventaja del funcionamiento actual que no logro visualizarla?

Saludos