2008-11-16
SSLアクセラレータ配下のapacheで、アクセスがhttpかhttpsかを判別する方法
少し前に試行錯誤して現在はひとまず解決したのですが、同じようにはてなで悩んでた人がいるみたいなので、自分の設定例を軽くまとめてみる。
SSLアクセラレータ配下にあるapache上でクライアントからのアクセスがhttpsかhttpであるかの判別をする方法はありますか?
mod_rewriteを利用しhttpのアクセスをhttpsにリダイレクトする設定を考えていますが、SSLアクセラレータを経由してのアクセスとなるため、apacheへの接続は全てhttpとなります。
回答にもあるように、恐らくapache単独では解決できませんが、SSLアクセラレータの設定と組み合わせれば可能です。それも拡張ヘッダやmod_rewriteなどの特別な仕組みは使用せずに。ただし、ここで書いてるのはSSLアクセラレータ付きのロードバランサ(以下、LB)を使用してる例なので、他の全てのSSLアクセラレータには当てはまらないかもしれません。でも似たようなことはできるかと。
あと、記事を書きながらhttps時のリダイレクト(自己参照URL)についても思い出して、それについても考慮して書きました。単にportを判別するだけならもっと簡単で良さげな気もしますが、長々と書いちゃっています。
設定
とりあえず先に結論を。
LB,SSLアクセラレータの設定
実サーバにhttp/httpsのリクエストを送信する際に、転送先のポート番号をそれぞれ個別に設定する。例えば
- httpは80番
- httpsは8443番 *1
言い換えると、http/httpsともに実サーバの80番にしか送れない場合は判別できません。たぶん大抵の場合は大丈夫だと思います。
実サーバのapacheの設定
NameVirtualHostでポート番号を変えて、http用とhttps用の2つの設定を作ります。
後で詳しく書きますが自己参照URLとServerNameの設定が大事。apacheのServerNameのドキュメントにもこう書いています。
リバースプロキシやロードバランサやSSL負荷軽減装置のような、 SSLを処理するマシンの後ろでサーバを動かす場合は、 サーバが正しい自己参照 URLを確実に生成するように、 https:// スキームとクライアントが接続するポート番号を、 ServerName ディレクティブに指定してください。
Listen 80 Listen 8443 NameVirtualHost *:80 NameVirtualHost *:8443 # http用の設定 <VirtualHost *:80> ServerName www.hoge ## その他色々 </VirtualHost> # https用の設定 <VirtualHost *:8443> ServerName https://www.hoge ## その他色々 </VirtualHost>
schemeとport番号を明示的に書くならこう。
# http用の設定 <VirtualHost *:80> ServerName http://www.hoge:80 ## その他色々 </VirtualHost> # https用の設定 <VirtualHost *:8443> ServerName https://www.hoge:443 ## その他色々 </VirtualHost>
判別方法
こう設定しておけば、httpとhttpsで環境変数SERVER_PORTの値が変わります。cgi,phpなどで適当に出力すればわかります。
- http://www.hoge/ => 80
- https://www.hoge/ => 443
ここでhttpsの環境変数が8443ではなくて、443になっているのがポイントです。
しているので、8443になりそうですが。。。
以下、それの補足です。
ServerNameと自己参照URL
これを理解するまで色々試行錯誤しました。詳細はapacheの以下ドキュメントを参照。
- ServerName
- UseCanonicalName
- UseCanonicalPhysicalPort
- mod_dir
なぜhttps用のVirtualHostのServerNameにhttps://のschemaを指定しているのか。
話がややこしくならないように、ここでは以下のapacheのデフォルト設定が入ってるとします。
UseCanonicalName Off UseCanonicalPhysicalPort Off
そして、ServerNameに他の設定をした例を紹介します。
ServerNameにschemaを指定せず、かつポート番号を書かない場合
通常のVirtualHostのように設定すると、以下のようになると思います。
# https <VirtualHost *:8443> ServerName www.hoge ## 残りhttps用の設定 </VirtualHost>
このとき、clientからhttps://www.hoge/にアクセスされた場合の、apacheの自己参照URLはhttp://www.hoge/になっていると思われます。すると以下の問題が起こります。
1番はそのままですね。本エントリの条件を満たしてないので問題外。2番は例を見てもらったほうがわかりやすいと思います。
"/"なしのディレクトリにアクセスした場合、
apacheデフォルトではmod_dirのDirectorySlashが働いて"/"が補完されます。このときにclientに返されるURLは、自己参照URLに/が補完された形です。こんな感じです。
※ はてなグループがSSLアクセラレータを使っているかは知りませんが、httpにリダイレクトするという例で紹介します。
- https://fragments.g.hatena.ne.jp/hogem https://のスラッシュなしにアクセスすると
- http://fragments.g.hatena.ne.jp/hogem/ http://にリダイレクト
opensslで確認するとよくわかります。
$ openssl s_client -connect fragments.g.hatena.ne.jp:443 -state (中略) HEAD /hogem HTTP/1.0 host: fragments.g.hatena.ne.jp HTTP/1.1 302 Found Date: Fri, 14 Nov 2008 12:22:30 GMT Server: Apache/2.2.3 (CentOS) Location: http://fragments.g.hatena.ne.jp/hogem/ X-Framework: Hatena/2.0 Content-Type: text/html; charset=iso-8859-1 Vary: Accept-Encoding Connection: close SSL3 alert read:warning:close notify closed SSL3 alert write:warning:close notify
302でhttpのURLが返ってきています。
ServerNameに8443のポート番号を明示的に指定する場合
最初はこの設定にしていました。この設定だとclientがhttpsに来た場合にSERVER_PORTを8443で取れるから。ただ、ServerNameの説明を読み直して、"これはひどい"状態になっていることが確認できたので慌てて元に戻しました。
同じようにclientからhttps://www.hoge/にアクセスされた場合を考えます。この設定だとapacheの自己参照URLがhttp://www.hoge:8443 になります。そのため
- 環境変数で取得できるSERVER_PORTが8443になってhttpとhttpsは判別できる、、、が!
- リダイレクトするとhttp://www.hoge:8443/directory/のようなURLになる
opensslで確認すると302でLocatin: http://www.hoge:8443/directory/ が返ってくるのが確認できます。8443番ポートなんてのは通常FWで閉じるのでアクセスすら出来ません。おまけに内部の仕組みが出てカッコ悪いですね。あわてて修正した苦い記憶が。。。
まとめ
httpかhttpsかを判別する方法。
- SSLアクセラレータ: httpとhttpsのポート番号を変える
- apache: httpとhttpsでポート番号を変えたNameVirtualHostを設定する
- httpsのVirtualHostのServerNameはhttps://のschemeを明示的に指定する
20090323追記
よくよく考えたらこんな面倒なことしてポート番号を見なくてもいいのではないかということに気が付いた。mod_envで適当な環境変数作るだけでいい?
https用のVirtualHost内で
Setenv X_HTTPS ON
とか
Setenv HTTPS ON
とかを設定して、後はプログラム側で$ENV{X_HTTPS}を判定するだけ。(phpは$_SERVER["HTTPS"] でHTTPSを判別してると思うので後者のほうがいいかも?本当のSSLじゃないので個人的には環境変数 HTTPS を設定するのは気持ち悪いですが)
この場合でもやはりhttpとhttps用のvirtualhostをわけることは必須ですね。というか、わけなかった場合、DocumentRootやCustomLogの設定まで全て同じになるので、ポート番号を判別したくなくても個別に設定したほうが良いのか。
購入: 4人 クリック: 32回
- 680 http://www.google.co.jp/url?sa=t&rct=j&q=sslアクセラレータ バーチャルホスト&source=web&cd=1&ved=0CC8QFjAA&url=http://d.hatena.ne.jp/hogem/
- 471 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCoQFjAA&url=http://d.hatena.ne.jp/hogem/20081116/1226840713&ei=MrZET8XvGMe3iQe-jsWNAw&usg=AFQjCNHDAGydcAnA649cXoHmAV1JukuIEQ&sig2=IbfwvBWunTt54P7wNzS5Sw
- 357 http://www.google.co.jp/search?q=sslアクセラレータ+apache&btnG=検索&hl=ja&lr=&client=firefox-a&rls=org.mozilla:ja:official&hs=sWF&sa=2
- 308 http://www.google.co.jp/search?hl=ja&q=sslアクセラレーター ヘッダー&lr=&aq=f&oq=
- 222 http://okyuu.com/ja/tips/4257
- 198 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4GGLL_ja&q=apache+ServerName+遅い
- 177 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&cts=1331268153168&ved=0CFAQFjAB&url=http://d.hatena.ne.jp/hogem/20081116/1226840713&ei=JYpZT_zXJfHsmAWI9PG6DQ&usg=AFQjCNHDAGydcAnA649cXoHmAV1JukuIEQ
- 176 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&cts=1331118766825&ved=0CEIQFjAD&url=http://d.hatena.ne.jp/hogem/20081116/1226840713&ei=GEJXT_DaJsP2mAW87djQDw&usg=AFQjCNHDAGydcAnA649cXoHmAV1JukuIEQ&sig2=lzhwwNx-18KXTwGdhmcEvA
- 156 http://www.google.co.jp/search?hl=ja&source=hp&q=sslアクセラレータ&lr=&btnG=Google+検索
- 149 http://search.yahoo.co.jp/search?p=SSLアクセラレータ+Apache&search.x=1&fr=top_ga1&tid=top_ga1&ei=UTF-8