Redireccionar a SSL solo si el navegador admite SNI

20

Tengo Apache 2.2 con mod_ssl y un montón de sitios en HTTPS en el mismo IP / puerto con VirtualHosting, por lo que el cliente debe ser compatible con SNI para conectarse a esos hosts virtuales.

Me gustaría configurar mi servidor de la siguiente manera:

Cuando un usuario escribe www.dummysite.com y su navegador admite SNI (Indicación de nombre del servidor), cualquier solicitud HTTP se redirige a https://donde se envía un encabezado HSTS. Pero si el navegador no admite SNI, entonces la solicitud es atendida por HTTP.

La regla anterior, tal como está, es en realidad una regla alternativa para aquellas personas que aún ejecutan navegadores antiguos, ya que Mozilla y Chrome no tienen este problema, solo para evitar dejar a estos usuarios fuera del sitio.

Me gustaría hacer esto redirigiendo en el nivel de configuración de Apache, tal vez con un filtro en el agente de usuario. No me gustaría tocar las aplicaciones en ejecución, excepto asegurarme de que no haya referencias directas de http: // (de lo contrario, implican una advertencia de seguridad)

[Editar] (al editar la pregunta, olvidé la pregunta): ¿cuál es la lista de agentes de usuario con SNI para redirigir?

usr-local-ΕΨΗΕΛΩΝ
fuente

Respuestas:

20

Dado que SNI ocurre durante el protocolo de enlace SSL / TLS, no es posible detectar el soporte del navegador cuando el cliente se conecta a HTTP.

Entonces tienes razón; Un filtro de agente de usuario es la única forma de hacerlo.

La gran pregunta es si desea actuar en una lista negra contra los navegadores que sabe que no escuchará SNI, o una lista blanca de navegadores que se sabe que lo admiten. Los dispositivos oscuros o nuevos que no pueden usar el sitio parecen ser un factor decisivo, por lo que diría que la lista blanca podría ser la mejor opción.

En tu HTTP <VirtualHost>:

# Internet Explorer 7, 8, 9, on Vista or newer
RewriteCond %{HTTP_USER_AGENT} MSIE\s7.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s8.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s9.*Windows\sNT\s6 [OR]
# Chrome on Windows, Mac, Linux
RewriteCond %{HTTP_USER_AGENT} Windows\sNT\s6.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Macintosh.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Linux.*Chrome [OR]
# Firefox - we'll just make the assumption that all versions in the wild support:
RewriteCond %{HTTP_USER_AGENT} Gecko.*Firefox
RewriteRule ^/(.*)$ https://ssl.hostname/$1 [R=301]

Aquí también está la opción de la lista negra: tenga en cuenta que esto corre el riesgo de enviar un cliente que no usa SNI a un sitio que necesita SNI, pero que, por otro lado, enviará a los usuarios algo nuevo como IE 10 a la derecha sitio:

# IE 6
RewriteCond %{HTTP_USER_AGENT} !MSIE\s6
# Windows XP/2003
RewriteCond %{HTTP_USER_AGENT} !Windows\sNT\s5
# etc etc
RewriteRule ^/(.*)$ https://ssl.hostname/$1 [R=301]

Hay muchos navegadores por ahí. He sido bastante suelto con las expresiones y no he cubierto muchos navegadores, esto podría convertirse en una pesadilla para mantener.

Cualquiera que sea la opción que elijas ... ¡buena suerte!

Shane Madden
fuente
1
¡Excelente! Probé con Opera Mobile (que cumple con SNI pero no está en la lista) y no redirige. ¡Con mi Firefox, redirige!
usr-local-ΕΨΗΕΛΩΝ
66
Sugiero modularizar esta solución con la directiva BrowserMatch de mod_setenvif httpd.apache.org/docs/2.2/mod/mod_setenvif.html . Use BrowserMatch para establecer una variable de entorno supports_sni = y, luego escriba RewriteCond% {ENV: supports_sni} = y. De esa forma, puede reutilizar la lógica de detección de SNI para cualquier otra RewriteRules que pueda tener.
200_success
@ 200_success ¡Buena idea!
Shane Madden
8

Mi solución es esta:

  # Test if SNI will work and if not redirect to too old browser page
  RewriteCond %{HTTPS} on
  RewriteCond %{SSL:SSL_TLS_SNI} =""
  RewriteRule ^ http://www.example.com/too-old-browser [L,R=307]

Si un navegador antiguo sin SNI intenta acceder a https://www.example.com/ *, primero arrojará un error en el navegador, que no puede evitarse hasta que Apache responda a un navegador que no sea SNI que no conoce qué sitio está solicitando. Luego, redirige a una página que le dice al usuario que su navegador es demasiado antiguo (siempre que los clics del usuario continúen en el sitio web).

Y para los usuarios con nuevos navegadores tengo

  #Test if new browser and if so redirect to https
  #new browser is not MSIE 5-8, not Android 0-3
  RewriteCond %{HTTPS} off
  RewriteCond %{HTTP_USER_AGENT} !MSIE\ [5-8]
  RewriteCond %{HTTP_USER_AGENT} !Android.*(Mobile)?\ [0-3]
  RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Eso excluye la mayoría de los navegadores antiguos, incluidos algunos como MSIE 5-8 en Vista (9+ es solo Vista / 7, por lo que es compatible con SNI). No es 100% (se ignora Symbian, etc.) pero debería funcionar para la mayoría. La minoría aún puede elegir aceptar el error del certificado.

malc_b
fuente
3

Por lo que sé, no hay realmente una buena manera de hacer esto: puede usar un regla mod_rewrite o similar condicionalmente basada en el User-agentencabezado, pero tendría que estar en un host NO SSL: si el navegador no lo hace admite SNI y va a un https://sitio seguro ( ) que obtendrá el comportamiento Apache de la vieja escuela de "Aquí está el primer certificado SSL que he asociado con esa dirección IP - ¡Espero que sea lo que querías!" - Si ese no es el certificado que esperaba el navegador, terminará con un mensaje de error sobre las discrepancias del nombre de host.

Básicamente, esto significa que las personas deben acceder a una página intersticial que no sea SSL que los redirigirá, posiblemente exponiendo cualquier dato que envíen en su solicitud. Esto puede o no ser un factor decisivo (usted dice que de todos modos los enviará a un sitio que no sea SSL si no son compatibles con SNI, por lo que supongo que no le importa mucho la seguridad. Si yo fuera diseñando un sistema que necesitaba SSL como capa de cifrado o autenticación, sería un poco más insistente al respecto ...)

Sin embargo, nada de eso impide que alguien marque el sitio seguro, y si usan un servicio de marcadores compartido o restauran sus marcadores en una máquina donde el navegador web no admite SNI, están de vuelta en el caso de errores potenciales por SSL .

voretaq7
fuente
1

Estaría tentado a resolver esta de tres maneras:

  1. RewriteRule Residencia en User-Agent encabezados.
  2. Cargue un https: // URI en un <SCRIPT> etiqueta en un VHost no predeterminado; Si la carga se realiza correctamente, es un poco de JS que vuelve a cargar toda la página en HTTPS.
  3. Enseñar a mis visitantes a usar algo como HTTPS Everywhere si esto es una prioridad para ellos, forzar HTTPS en las páginas donde debería ser necesario y esperar que todo salga bien al final.

De estos, personalmente me gusta el # 2 el mejor, pero eso implica modificar el código de sus sitios.

BMDan
fuente
0

Solo para cualquiera que lo necesite.

Si tiene varios hosts y desea que todos estén habilitados para SSL en VirtualHosting (y compró un certificado para cada uno), pruebe el nuevo mod_djechelon_ssl

$ cat /etc/apache2/mod_djechelon_ssl.conf 
RewriteEngine on
# Internet Explorer 7, 8, 9, on Vista or newer
RewriteCond %{HTTP_USER_AGENT} MSIE\s7.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s8.*Windows\sNT\s6 [OR]
RewriteCond %{HTTP_USER_AGENT} MSIE\s9.*Windows\sNT\s6 [OR]
# Chrome on Windows, Mac, Linux
RewriteCond %{HTTP_USER_AGENT} Windows\sNT\s6.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Macintosh.*Chrome [OR]
RewriteCond %{HTTP_USER_AGENT} Linux.*Chrome [OR]
# Firefox - we'll just make the assumption that all versions in the wild support:
RewriteCond %{HTTP_USER_AGENT} Gecko.*Firefox [OR]
#Safari iThing
RewriteCond %{HTTP_USER_AGENT} Mozilla.*iPhone.*Safari [OR]
RewriteCond %{HTTP_USER_AGENT} Mozilla.*iPod.*Safari [OR]
RewriteCond %{HTTP_USER_AGENT} Mozilla.*iPad.*Safari [OR]
RewriteRule ^/(.*)$ https://%{HTTP_HOST}/$1 [R=permanent,L]

Uso:

<VirtualHost ip:80>
ServerName www.yourhost.com

Include /path/to/mod_djechelon_ssl.conf

[plain old Apache directives]
</VirtualHost>

<VirtualHost ip:443>
ServerName www.yourhost.com

[SSL-related directives]

[Copy and paste directives from above host]
</VirtualHost>
usr-local-ΕΨΗΕΛΩΝ
fuente
0

Como publiqué aquí , solo puede probar el soporte SNI antes de solicitarlo. Es decir, no puede forzar a los usuarios a SNI HTTPS y luego retroceder si no lo admiten, porque recibirán un error como este (de Chrome en Windows XP) sin forma de proceder.

Entonces (desafortunadamente) el usuario tiene que comenzar con una conexión HTTP insegura y luego actualizarse solo si admite SNI.

Puede detectar el soporte SNI a través de:

  1. Script remoto
    Desde su página HTTP simple, cargue un archivo <script>desde su servidor SNI HTTPS de destino y si el script se carga y ejecuta correctamente, sabe que el navegador admite SNI.

  2. Cross-Domain AJAX (CORS)
    Similar a la opción 1, puede intentar realizar una solicitud AJAX entre dominios desde la página HTTP al HTTPS, pero tenga en cuenta que CORS solo tiene un soporte de navegador limitado .

  3. Sniff the user-agent
    Este es probablemente el método menos confiable, y tendrá que decidir entre tener una lista negra de navegadores (y sistemas operativos) que no son compatibles, o una lista blanca de sistemas conocidos que lo hacen.

    Sabemos que todas las versiones de IE, Chrome y Opera en Windows XP y versiones posteriores no son compatibles con SNI. Consulte CanIUse.com para obtener una lista completa de los navegadores compatibles .

Simon East
fuente