mod_actionsを使ってドキュメントや画像、Flashファイルを保護する | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

会員制のサービスなど、ログインした状態でないとコンテンツをユーザーに見せたくないという仕様はよくありますが、HTMLなどはプログラムから簡単に保護ができるものの、ドキュメントや画像やFlashファイルなどを保護するのは若干の工夫が必要になってきます。


今回は、Apacheのモジュールの一つであるmod_actions を使って、ドキュメントルート以下に置いているWordやExcelファイル、画像やFlashなどプログラムから保護しにくいファイルに対して、セキュリティ実装を簡単に行ってみたいと思います。



一般的なドキュメントや画像ファイルを保護する実装


mod_actionsでの実装を行ってみる前に、ドキュメントや画像やFlashファイルなどをログインしていないユーザーから保護するためにはどういった方法があるかを考えてみます。


最も簡単な方法は、Basic認証をかませてログインしていないユーザーに強制的にIDとパスワードを求めるというものがあります。

指定のディレクトリ以下を全てBasic認証で保護するので、ユーザーがダイレクトにドキュメントファイルにアクセスしても、正規のログイン手段と同様にIDとパスワードを求めることができます。

しかしこれは、認証方法が固定化されるとともに、独自の認証を実装している環境では適用が難しかったりもします。


もう一つはPHPなどのプログラムを通してファイルを保護する方法があります。


<html>
<body>
<img src="load_image.php?img_file=hoge.gif" />
</body>
</html>

<?php

// 認証チェック
if (empty($_COOKIE['my_session'])) {
    header('HTTP/1.0 401 Unauthorized');
    echo "Unauthorized. Please login";
} else {
// ログインした状態であれば画像ファイルを呼び出し
    $file = pathinfo($_REQUEST['img_file']);
    readfile("/var/www/no-htdocs/images/" . $file['basename']);
}


imgタグ内でPHPファイルを指定し、load_image.phpによりドキュメントルート外に保存しているイメージファイルを読み込んで出力するというような実装になります。

ドキュメントルート外にイメージファイルを保存しておくことにより、ダイレクトにその画像ファイルにアクセスすることができません。

また、上記の例では簡単な実装にしていますが、ログイン時にセットされたCOOKIE情報などからログインされているかどうかをチェックすることで、このプログラムを悪用して画像ファイルが呼び出されることが無いようにしておく必要もあるでしょう。

しかし、この場合でも画像ファイルの保存先とその呼び出し方法が特殊となることにより、コンテンツが作りこみにくい状態になってしまいます。



mod_actionsでファイルを保護するためのセキュリティ実装を行う


mod_actionsを使えば、.htaccessファイルに数行書くのと認証チェック用のプログラムを配置するだけで、呼び出しもとのHTMLファイルには手を加えずにファイルを保護することができます。

まずは、Apacheの設定ファイルからmod_actionsのモジュールが呼び出されているか確認しておきます。


LoadModule actions_module modules/mod_actions.so

次に、セキュリティ保護したいディレクトリ直下に.htaccessファイルを配置します。


Action image/gif /check_login.php


上記のように、Actionディレクティブの後ろにファイルのMIMEタイプとそのMIMEに該当した場合の呼び出し先(check_login.php)を指定しておきます。

指定のMIMEに引っかかったらプログラムをコールしてくれるといったことがApacheの中で実装可能になるわけです。

これだけで、GIFファイルにアクセスされたらcheck_login.phpファイルが自動的に呼び出されます。


<?php

// 認証チェック
if (empty($_COOKIE['my_session'])) {
    header('HTTP/1.0 401 Unauthorized');
    echo "Unauthorized. Please login";
} else {
// ログインした状態であれば元ファイルを呼び出し
    readfile($_SERVER['DOCUMENT_ROOT'] . $_SERVER['PATH_INFO']);
}


上記の場合も簡単な認証チェック用のプログラムになりますが、ログイン時にセットされるはずのCOOKIEが存在しなかった場合は401のHTTPステータスコードとともにエラーメッセージを、正常にログインされた状態である場合は画像ファイルを呼び出して出力をしています。

この状態で、画像ファイルを呼び出してみます。

呼び出すHTMLは、単純にこんな感じで書いています。


<html>
<body>
<img src="/images/image.gif">
</body>
</html>


これを、ログインしていない(COOKIEがセットされていない)状態でアクセスしてみて、その時の通信状況をFireBugで見てみると、


- FireBugで通信状態を見た例(ログインしていない場合)

A Day In The Boy&#39;s Life-mod_actionsでセキュリティ保護


画像だけがHTTPステータス401が返され、ブラウザ上に表示されません。

また、mod_actionsを使わない場合で説明したHTMLとは違い、小細工なしのそのままのHTMLで実装することを可能にしてくれます。
デザイナーさんと分業するといった場合に、特にややこしい仕様を取り決めておく必要もなくなります。


ここでは、画像ファイルをセキュリティ保護する実装例を書いてみましたが、HTML自体であったりFlashやドキュメントファイルももちろん対応可能です。

それぞれ、.htaccessにそのファイルのMIMEを指定するだけで実装できます。


# Word File
Action application/msword /check_login.php
# Power Point
Action application/vnd.ms-powerpoint /check_login.php
# Excel File
Action application/vnd.ms-exce /check_login.php
# Flash File
Action application/x-shockwave-flash /check_login.php

ただし、当然ながら保護対象を増やせば増やすほど処理数が増えるためオーバーヘッドが大きくなってしまいます。

必要最低限の対象に絞るか、保護するファイルを保管するディレクトリを固定し、そのディレクトリに対して.htaccessファイルを配置するなどの工夫は必要になってきます。


また、こちらで検証してみたところPHPファイル自体はActionによりフックして別のPHPプログラムをコールするというようなことはできませんでした。

PHP自体のMIMEがうまく認識してくれないようです。(httpd.confに記述しているapplication/x-httpd-phpとかを指定してもダメ)

.phpの拡張子でActionをフックして、コールされる認証プログラムなどを別の拡張子にてPHPを動作可能にしておけばうまくいくかもしれません。

ただ、PHP自体には認証ロジックなどを入れることは可能なので、あまりmod_actionsを通すことの意味はない気もします。


ということで、一般的にロジックなどを埋め込むことができないファイルに対してログインのチェックなど何らかの前処理を行わせたい、といった場合は今回のmod_actionsを使えば既存の環境にあまり手を加えることなしに、簡単に実装することが可能になります。