ある異邦人の技術メモ

2008-02-26

SSLと非SSLページの自動切換え

SSLアクセスして欲しいページと、非SSLアクセスして欲しいページが混在するサイト(普通のサイト)をつくるとき、以下のようになっているとユーザにも親切ですし、ものづくりが楽になります。

特にものづくりにおいては、逆にこうなっていないと、HTML上にhttp://などから始まる絶対パスを書かねばならず、結構面倒なことになります。

今回は、mod_rewriteを使って上記設定をしましたというお話です。


2つの方法

さて、上記のような要件を満たす仕掛けを実現するには、以下2つのアプローチが可能です。

  1. APサーバレベルでSSL/非SSLリダイレクトを実装。
  2. WebサーバSSL/非SSLリダイレクトを設定して。APサーバSSLのことは意識せず常にhttpを処理しているつもりになる。

APサーバで処理する場合

APサーバがWEBサーバも兼ねるようなときはこの方式もアリかなと思います。また、Web/Apが分離していても開発環境と本番環境がまったく同じ環境であればこの方式に別に不便は感じないかもしれません。実際私はこれまでこの方法しか知らずにいました。Railsの場合はssl_requirementプラグインを使えば手軽に実装できます。

しかし、私はRailsやらJavaで物を作るとき、自分はEclipseを使ってlocalhost上にWebrickやらTomcatサーバを動かして開発します。それで出来たものをSubversionにコミットして、そこから実サーバマシンにリリース&デプロイするっていうスタイルですね。また、リリース環境はApache + MongrelとかApache + Tomcatとか、必ずApacheを前に持ってくるWeb/Ap分離構成にします。そういう場合、実はこの方式はちょっとつらい。

なぜなら:

  • localhostで動かす開発用簡易サーバSSLに対応してなかったりする。対応してたとしても、設定を覚える気にならない。
  • がんばって設定したとしても、開発用サーバは8080だとか8443だとか、80/443以外のポートで動かすことが多い。それだとURLの書き換えにおいては、httpという文字列とhttpsという文字列を入れ替えるだけでなくポート情報も書き換えなくてはならない。
  • がんばってポート番号まで書き換える実装をしたとしても、その実装は(普通は素直に80/443で使う)本番環境で役に立たない。
  • ていうか、そもそもSSLの処理(証明書発行やら暗号化・複合など)をAPサーバまで持ってくるのか?(Webサーバが暇になりすぎで実用的でないし、また、やり方もわからず、そもそもできるのかもあやしい。)

ということで自分の場合、冷静に考えれば次に述べるようにSSL/非SSLリダイレクト処理はWebサーバレベルでやりたかったわけです。が、一生懸命railsのssl_requirementプラグインを試したりしてしまったのは秘密です^^

そもそも、SSL/非SSLリダイレクトなんていうものをちゃんとやったこともなく、htmlにゴリゴリ本番環境用の絶対URLを書いて、「開発環境では動かなーい;;」なんてやっていたのも、秘密です^^

Webサーバで処理する場合

ローカルPC上のEclipseで開発して、Eclipseプラグインから起動する簡易サーバで検証してSubversionリポジトリにリリースすすようなスタイルの開発をしている場合は、こちらの方法のほうがよさそうです。即ちWebサーバSSL/非SSLリダイレクトを実装して、APサーバSSLのことは意識せず常にhttpを処理しているつもりになるアーキテクチャです。

さて、私が使うWebサーバはいつでもApache。そしてApacheリダイレクトといえば、mod_rewriteです。今回mod_rewriteを使ってリダイレクトを実現しました。

ディレクトリごとにSSL/非SSLを設定する方法を以下に記します。

たとえば、ログインと管理画面ということで、 それに対応する /login, /adminというURLパスを定義していたとしましょう。そしてそのパス以下はSSLでアクセスしてほしくて、それ以外のページは非SSLアクセスしてほしい場合を考えます。


そんなときは、以下のように書けばいいかなと思います。

<IfModule mod_rewrite.c>
        RewriteEngine On
	#ログ出力したければ・・
        #RewriteLog /var/log/apache2/rewrite.log
        #RewriteLogLevel 1  

	#SSLアクセスしてほしいページ
        RewriteCond %{SERVER_PORT} !^443$
        RewriteRule ^(/(login|admin)/.*)?$ https://%{HTTP_HOST}$1 [L,R]

	#非SSLアクセスしてほしいページ
        RewriteCond %{SERVER_PORT} ^443$
        RewriteRule !^/(login|admin) - [C]

        RewriteCond %{SERVER_PORT} ^443$
        RewriteRule ^(.*)?$ http://%{HTTP_HOST}$1 [L,R]
</IfModule>

要するにこういうことです。

	#SSLアクセスしてほしいページ
        RewriteCond %{SERVER_PORT} !^443$
        RewriteRule ^(/(login|admin)/.*)?$ https://%{HTTP_HOST}$1 [L,R]

443以外のポート(非SSL)で /login/や/admin/から始まるパスにアクセスがきたら、https://で始まるURLにリライト


	#非SSLアクセスしてほしいページ
        RewriteCond %{SERVER_PORT} ^443$
        RewriteRule !^/(login|admin) - [C]

443ポート(SSL)で /login/や/admin/から始まらないパスにアクセスがきたら次のルールを適用([C])

        RewriteCond %{SERVER_PORT} ^443$
        RewriteRule ^(.*)?$ http://%{HTTP_HOST}$1 [L,R]

443ポート(SSL)でのリクエストはhttp://から始まるURLにリライト([L,R])


この方法ならばSSLのことを考えるのはインフラ屋さん(サーバ設定するひと)だけに任せて、アプリ屋さん(プログラム書く人)やデザイナさん(HTML作る人)はSSLのこと何も考えないですむので、中〜大規模プロジェクトなんかでもこの方法のほうが幸せなんだろうなと想像します。

flontierflontier 2009/03/09 17:12 はじめまして。
mod_rewriteで、同様の事をしようと思っているのですが
http→httpsへのリライトはできるのですが、https→httpへの変換が反応しません。
下記2行のみとして、実施しているのですが
下記は"443ポート(SSL)でのリクエストはhttp://から始まるURLにリライト([L,R])"
との認識で宜しいでしょうか?

RewriteCond %{SERVER_PORT} ^443$
RewriteRule ^(.*)?$ http://%{HTTP_HOST}$1 [L,R]

環境はCentOS5.2、apache2.2になります。
宜しければ、考えられる要因を教授頂ければと思います。

MC6800MC6800 2009/09/17 18:06 flontier 様、浦島レスで恐縮です。
当方も同様な事象で悩みましたが、http から https へリダイレクトを行う設定は httpd.conf に記述し、
逆に https から http へリダイレクトを行う設定は httpd-ssl.conf に記述すれば良いようです。
なので、以下の設定を httpd-ssl.conf に記述すれば意図した動作になるものと思います。
注:httpd-ssl.conf に記述する際は、VirtualHost ディレクティブ内に記述する必要があります。

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteLog "/logs/rewrite.log"
RewriteLogLevel 1
RewriteCond %{SERVER_PORT} ^443$
RewriteRule ^(.*)?$ http://%{HTTP_HOST}$1 [L,R]
</IfModule>

既に解決済みかもしれませんが、気になってしまったので書き込みさせていただきました。
失礼いたしました。m(__)m

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証