Redirecionar para SSL somente se o navegador suportar SNI

20

Eu tenho o Apache 2.2 com mod_ssl e vários sites em HTTPS no mesmo IP / porta do VirtualHosting, portanto, o cliente deve suportar o 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 HTTP é redirecionada para https://onde um cabeçalho HSTS é enviado. Mas se o navegador não suportar SNI, a solicitação será atendida por HTTP.

A regra acima, declarada como está, é na verdade uma regra de fallback para as pessoas que ainda executam navegadores antigos, pois o Mozilla e o Chrome não têm esse problema, apenas para evitar deixar esses usuários fora 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 me certificando de que nenhuma referência direta http: // esteja presente (caso contrário, eles implicam em um aviso de segurança)

[Edit] (ao editar a pergunta que eu esqueci a pergunta): o que é a lista de agentes de usuário SNI habilitados para redirecionar?

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

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ê deseja atuar em uma lista negra de navegadores que você sabe que não escutará o SNI ou em uma lista de permissões de navegadores conhecidos por suportá-lo. Dispositivos obscuros ou novos, impossibilitados de usar o site, parecem um negócio, 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 também está a opção da lista negra - lembre-se de que isso corre o risco de enviar um cliente que não usa o SNI para um site necessário ao SNI, mas, por outro lado, enviará usuários de algo novo como o IE 10 para a direita Lugar, colocar:

# 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 me sentido bem com as expressões e não abordado muitos navegadores - isso pode se transformar no pesadelo de manter.

Qualquer opção que você escolher .. boa sorte!

Shane Madden
fonte
11
Ótimo! Testei com o Opera Mobile (que é compatível com SNI, mas não está na lista) e não é redirecionado. Com o meu Firefox, ele redireciona!
Usr-local-
6
Sugiro modularizar esta solução com a diretiva BrowserMatch de mod_setenvif httpd.apache.org/docs/2.2/mod/mod_setenvif.html . Use o BrowserMatch para definir uma variável de ambiente support_sni = y, em seguida, escreva RewriteCond% {ENV: support_sni} = y. Dessa forma, você pode reutilizar a lógica de detecção de SNI para quaisquer outras RewriteRules que você possa ter.
200_success
@ 200_success Boa ideia!
Shane Madden
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 https://www.example.com/ *, ele lançará um erro no navegador primeiro, o que não pode ser evitado, desde que o apache responda a um navegador que não seja SNI. qual site ele está solicitando. Em seguida, ele é redirecionado para uma página informando ao usuário que seu navegador é muito antigo (desde que os cliques do usuário continuem no 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, portanto, suporta SNI). Não é 100% (o symbian é ignorado etc.), mas deve funcionar para a maioria. A minoria ainda pode optar por aceitar o erro de certificado.

malc_b
fonte
3

Pelo que sei, não há realmente uma boa maneira de fazer isso - você pode usar uma regra mod_rewrite ou semelhante condicionalmente com base no User-agentcabeçalho, mas ela teria que ser em um vhost não SSL: Se o navegador não suporte ao SNI e ele acessa um https://site seguro ( ), obtendo 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 é o certificado que o navegador esperava, você terminará com 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 os dados que estão enviando em sua solicitação. Isso pode ou não ser um desagregador (você diz que os enviará para um site não SSL de qualquer maneira, se eles não suportarem SNI, por isso suponho que você não se importe muito com segurança). Ao projetar um sistema com necessidade de SSL como uma camada de criptografia ou autenticação, eu seria um pouco mais insistente quanto a isso ...)

Porém, nada disso impede alguém de marcar o site como favorito - e, se usarem um serviço de favoritos compartilhado ou restaurarem seus favoritos em uma máquina em que o navegador da Web não for compatível com SNI, eles voltarão ao caso de Potencial para SSL-Erros .

voretaq7
fonte
1

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

  1. RewriteRulecom base em User-Agentcabeçalhos.
  2. Carregar um https: // URI em uma <SCRIPT>tag em um VHost não padrão; se o carregamento for bem-sucedido, é um pouco de JS que recarrega a página inteira em HTTPS.
  3. Ensine meus visitantes a usar algo como HTTPS Everywhere, se isso for uma prioridade para eles, force o HTTPS nas páginas onde for necessário e espere que tudo dê certo no final.

Destes, eu pessoalmente gosto do segundo melhor, mas isso envolve a modificação do código dos seus sites.

BMDan
fonte
0

Apenas para quem precisa.

Se você possui vários hosts e deseja que todos eles sejam habilitados para SSL no VirtualHosting (e você comprou um certificado para cada um), tente 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>
usr-local-ΕΨΗΕΛΩΝ
fonte
0

Como publiquei aqui , você só pode testar o suporte ao SNI antes de solicitá-lo. Ou seja, você não pode forçar os usuários a entrar no SNI HTTPS e fazer o backup se eles não o suportarem, porque receberão um erro como este (do Chrome no Windows XP) sem nenhuma maneira de prosseguir.

Portanto (infelizmente) o usuário precisa realmente começar por uma conexão HTTP insegura e ser atualizado apenas se suportar SNI.

Você pode detectar o suporte SNI através de:

  1. Script remoto
    Na sua página HTTP simples, carregue um <script>do servidor SNI HTTPS de destino e, se o script carregar e executar corretamente, você saberá que o navegador suporta SNI.

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

  3. Detectar o agente do usuário
    Este é provavelmente o método menos confiável, e você precisará decidir entre ter uma lista negra de navegadores (e sistemas operacionais) que não são compatíveis ou uma lista branca de sistemas conhecidos que o fazem.

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

Simon East
fonte