Redirecionar para SSL somente se o navegador suportar SNI

19

Eu tenho o Apache 2.2 com mod_ssl e um monte de sites em HTTPS no mesmo IP / port com VirtualHosting, então o cliente deve suportar SNI para se conectar a esses hosts virtuais.

Gostaria de configurar meu servidor da seguinte maneira:

Quando um usuário digita www.dummysite.com e seu navegador suporta SNI (Server Name Indication), qualquer solicitação de HTTP é redirecionada para https:// onde um cabeçalho de HSTS é enviado. Mas se o navegador não suportar SNI, a solicitação será atendida pelo HTTP.

A regra acima, declarada como está, é na verdade uma regra alternativa para as pessoas que ainda executam navegadores antigos, pois o Mozilla e o Chrome não têm esse problema, apenas para evitar que esses usuários saiam do site.

Eu gostaria de fazer isso redirecionando no nível de configuração do Apache, talvez com um filtro no agente do usuário. Eu não gostaria de tocar em aplicativos em execução, exceto garantir que nenhuma referência http: // direta esteja presente (caso contrário, eles implicam em um aviso de segurança)

[Editar] (ao editar a pergunta, esqueci a pergunta): qual é a lista de agentes de usuários habilitados para SNI a serem redirecionados?

    
por usr-local-ΕΨΗΕΛΩΝ 16.05.2012 / 22:34

6 respostas

20

Como o SNI ocorre durante o handshake SSL / TLS, não é possível detectar o suporte ao navegador quando o cliente se conecta ao HTTP.

Então, você está certo; um filtro de agente do usuário é a única maneira de fazer isso.

A grande questão é se você quer atuar em uma lista negra contra navegadores que você sabe que não vai ouvir SNI, ou uma lista branca de navegadores que são conhecidos por suportá-lo. Dispositivos obscuros ou novos, sendo incapazes de usar o site, parecem ser um fator decisivo, então eu diria que a lista de permissões pode ser a melhor opção.

No seu 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]

Aqui está a opção de lista negra também - tenha em mente que isso corre o risco de enviar um cliente que não usa SNI para um site necessário para SNI, mas por outro lado, enviará usuários de algo novo como o IE 10 para o lugar certo:

# 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]

Existem muitos navegadores por aí. Eu tenho sido muito solto com as expressões e não cobri um monte de navegadores - isso pode se transformar em um grande pesadelo para manter.

Qualquer que seja a opção escolhida ... boa sorte!

    
por 16.05.2012 / 22:58
8

Minha solução é 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]

Se um navegador antigo sem SNI tentar acessar o link *, ele lançará um erro no navegador primeiro, o que não pode ser evitado desde até que o apache responda a um navegador que não seja o SNI, ele não sabe qual site ele está pedindo. Em seguida, ele redireciona para uma página informando ao usuário que seu navegador é muito antigo (contanto que o usuário clique em continuar para o site).

E para usuários com novos navegadores eu tenho

  #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]

Isso exclui a maioria dos navegadores antigos, incluindo alguns como o MSIE 5-8 no Vista (9+ é apenas o Vista / 7 e suporta o SNI). Não é 100% (symbian é ignorado, etc.), mas deve funcionar para a maioria. A minoria ainda pode optar por aceitar o erro do certificado.

    
por 10.10.2014 / 18:21
3

Até onde sei, não há realmente uma boa maneira de fazer isso - você pode usar um mod_rewrite rule ou similar condicionalmente com base no cabeçalho User-agent , mas teria que estar em um vhost NON-SSL: Se o navegador não suportar SNI e ele vai para um site seguro ( https:// ) que vai ter o comportamento Apache da velha escola de "Aqui está o primeiro certificado SSL que associei a esse endereço IP - Espero que seja o que você queria!" - Se esse não for o certificado que o navegador esperava, você receberá uma mensagem de erro sobre incompatibilidade de nome de host.

Isso basicamente significa que as pessoas precisam acessar uma página intersticial não SSL que as redirecionará, possivelmente expondo todos os dados que estão enviando em sua solicitação. Isso pode ou não ser um disjuntor de negócio (você diz que vai enviá-los para um site não-SSL de qualquer maneira se eles não suportarem SNI, então eu suponho que você não se importe muito com segurança. Se eu fosse projetando um sistema que tinha uma necessidade de SSL como uma camada de criptografia ou autenticação, eu seria um pouco mais insistente sobre isso ...)

Nada disso impede alguém de marcar o site seguro - e, se usar um serviço de favoritos compartilhados ou restaurar seus favoritos em uma máquina em que o navegador da Web não suporta SNI, eles retornam ao Potencial para SSL. Caso -Errors.

    
por 16.05.2012 / 22:48
1

Eu ficaria tentado a resolver essa de três maneiras:

  1. RewriteRule com base nos cabeçalhos User-Agent .
  2. Carregue um https: // URI em uma tag <SCRIPT> em um VHost não padrão; se a carga der certo, é um pouco de JS que recarrega toda a página em HTTPS.
  3. Ensine meus visitantes a usar algo como o HTTPS Everywhere se isso for uma prioridade para eles, forçar o HTTPS nas páginas em que ele deve ser necessário e esperar que tudo funcione no final.

Destes, eu pessoalmente gosto do # 2 melhor, mas isso envolve modificar o código do seu site.

    
por 16.05.2012 / 22:55
0

Apenas para quem precisar.

Se você tiver vários hosts e quiser que todos eles sejam habilitados para SSL no VirtualHosting (e você comprou um certificado para cada um deles), experimente o novo 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>
    
por 17.05.2012 / 00:36
0

Como eu postei aqui , você só pode testar o suporte SNI anterior para exigir . Ou seja, você não pode forçar os usuários a usar o SNI HTTPS e depois retroceder caso eles não o suportem, porque eles receberão um erro como esse (do Chrome no Windows XP) sem nenhuma maneira de proceder.

Então (infelizmente) o usuário tem que começar de fato por uma conexão HTTP insegura e depois ser atualizado apenas se eles suportarem SNI.

Você pode detectar suporte SNI via:

  1. Script remoto
    Na sua página HTTP simples, carregue um <script> de seu servidor SNI HTTPS de destino e, se o script for carregado e executado corretamente, você sabe que o navegador suporta SNI.

  2. AJAX entre domínios (CORS)
    Semelhante à opção 1, você poderia tentar executar uma solicitação AJAX de vários domínios da página HTTP para o HTTPS, mas esteja ciente de que o CORS tem apenas limitado suporte ao navegador .

  3. Sniff o user-agent
    Este é provavelmente o método menos confiável, e você precisará decidir entre ter uma lista negra de navegadores (e sistemas operacionais) conhecida por não suportá-la, ou uma lista branca de sistemas conhecidos que o façam.

    Sabemos que todas as versões do IE, do Chrome & Opera no Windows XP e abaixo não suportam SNI. Consulte CanIUse.com para obter uma lista completa de navegadores compatíveis .

por 06.09.2016 / 07:30