web-dev-qa-db-ja.com

ブラウザがSNIをサポートしている場合にのみSSLにリダイレクトする

私はmod_sslを備えたApache 2.2と、VirtualHostingを備えた同じIP /ポート上のHTTPSの多数のサイトを持っているため、クライアントはこれらの仮想ホストに接続するためにSNIをサポートする必要があります。

サーバーを次のように構成したいと思います。

ユーザーがwww.dummysite.comとブラウザを入力すると、supports SNI(サーバー名表示)となり、HTTPリクエストはHSTSヘッダーが送信されるhttps://にリダイレクトされます。しかし、ブラウザサポートしていない SNIの場合、リクエストはHTTPによって処理されます。

上記のルールは現状のままですが、MozillaとChromeにはこの問題がないため、これらのユーザーを除外しないようにするため、実際には古いブラウザーを実行している人々のためのフォールバックルールですサイト。

おそらくユーザーエージェントのフィルターを使用して、Apache構成レベルでこのリダイレクトを実行したいと思います。直接のhttp://参照が存在しないことを確認することを除いて、実行中のアプリケーションに触れたくありません(そうでない場合、それらはセキュリティ警告を意味します)

[編集](私が忘れていた質問の編集中にthe質問):リダイレクトするSNI対応のユーザーエージェントのリストは何ですか?

SNIはSSL/TLSハンドシェイク中に発生するため、クライアントがHTTPに接続するときにブラウザーサポートを検出することはできません。

だから、あなたは正しいです。これを行う唯一の方法は、ユーザーエージェントフィルターです。

大きな問題は、SNIをリッスンしないことがわかっているブラウザーに対してブラックリストを実行するか、それをサポートすることがわかっているブラウザーのホワイトリストを実行するかです。あいまいな、または新しいデバイスがサイトを使用できないことは、契約違反のように思われるので、ホワイトリストの方が良いオプションだと思います。

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]

ここにもブラックリストオプションがあります。これは、SNIを使用しないクライアントをSNIが必要なサイトに送信するリスクがありますが、一方でIE 10を正しい場所に:

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

世の中にはたくさんのブラウザがあります。私は表現にかなりゆるんでいて、多くのブラウザーをカバーしていません-これは維持するのがかなり悪夢になるかもしれません。

どちらのオプションを選択しても..頑張ってください!

20
Shane Madden

私の解決策はこれです:

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

SNIのない古いブラウザーが https://www.example.com/ *にアクセスしようとすると、最初にブラウザーでエラーがスローされます。これは、Apacheが非SNIブラウザーは、どのサイトを要求しているかがわかりません。次に、ブラウザが古すぎることをユーザーに通知するページにリダイレクトします(ユーザーがWebサイトにアクセスし続ける限り)。

そして、私が持っている新しいブラウザを持つユーザーのために

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

これは、VistaのMSIE 5-8(9+はVista/7のみなのでSNIをサポートしている)など、古いブラウザーのほとんどを除外します。 100%ではありませんが(symbianは無視されます)、大多数で機能するはずです。少数派は依然として証明書エラーを受け入れることを選択できます。

8
malc_b

私が知っている限り、これを行うには本当に良い方法はありません-User-agentヘッダーに基づいて mod_rewriteルール または同様の 条件付き を使用できます、しかしそれは非SSL仮想ホスト上にある必要があります:ブラウザーがSNIをサポートしていない場合、セキュア(https://)旧式のApacheの動作を取得するサイト "ここに、そのIPアドレスに関連付けた最初のSSL証明書があります-それがあなたの望むものであることを願っています!" -それが証明書でない場合ブラウザは、ホスト名の不一致に関するエラーメッセージが表示されると予想していました。

これは基本的に、人々がリダイレクトする非SSLインタースティシャルページにアクセスする必要があることを意味します-リクエストで送信しているデータを公開する可能性があります。これは取引ブレーカーである場合とそうでない場合があります(SNIをサポートしていない場合は非SSLサイトに送信することになるので、セキュリティについてはそれほど気にしないと思います。暗号化層または認証層としてSSLを必要とするシステムを設計する場合、私はそれについて少し固執します...)

ただし、セキュリティで保護されたサイトをブックマークすることを妨げるものはありません。共有ブックマークサービスを使用したり、ブックマークをWebブラウザがSNIをサポートしていないマシンに復元したりした場合、SSLエラーの可能性のあるケースに戻ります。 。

3
voretaq7

これを3つの方法のうちの1つで解決したくなります。

  1. RewriteRuleUser-Agentヘッダーに基づいています。
  2. デフォルト以外のVHostの<SCRIPT>タグにhttps:// URIをロードします。ロードが成功した場合、HTTPSでページ全体をリロードするのは少しJSです。
  3. これを優先する場合は、HTTPS Everywhereなどを使用するように訪問者に教え、必要なページにHTTPSを強制し、最終的にすべてがうまくいくことを期待します。

これらのうち、個人的には#2が一番好きですが、これにはサイトのコードの変更が含まれます。

1
BMDan

それを必要とする人のためだけに。

複数のホストがあり、それらすべてをVirtualHostingでSSL対応にしたい場合(そしてそれぞれの証明書を購入した場合)、新しい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]

使用法:

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

ここに投稿したとおり 、SNIサポートのテストはそれを要求する前にのみ可能です。つまり、ユーザーがSNI HTTPSを強制的に実行できず、サポートしていない場合はフォールバックできません。続行できないため、このようなエラーが(Windows XPのChromeから)表示されるためです。

そのため、(残念ながら)ユーザーは実際には安全でないHTTP接続を介して開始し、SNIをサポートしている場合にのみアップグレードする必要があります。

SNIサポートは次の方法で検出できます。

  1. リモートスクリプト
    プレーンなHTTPページから、宛先SNI HTTPSサーバーから<script>をロードします。スクリプトがロードされて正しく実行されれば、ブラウザーがSNIをサポートしていることがわかります。

  2. クロスドメインAJAX(CORS)
    オプション1と同様に、HTTPページからHTTPSへのクロスドメインAJAXリクエストの実行を試みることができますが、CORSには 限られたブラウザーサポートのみ があることに注意してください。

  3. ユーザーエージェントの傍受
    これはおそらく最も信頼性の低い方法であり、サポートしないことがわかっているブラウザ(およびオペレーティングシステム)のブラックリストを使用するか、サポートする既知のシステムのホワイトリストを使用するかを決定する必要があります。

    Windows Chrome以下のIE、OperaおよびXPのすべてのバージョンがSNIをサポートしていないことはわかっています。サポートされているブラウザの完全なリストについては、 CanIUse.com]を参照してください

0
Simon East