アクセス制限ベーシック認証 ~パスワードでページを守ろう~

 ホームページを作る上で、特定の人にだけ見せたいページが出てくるでしょう。そのようなページでよく、アカウントとパスワードを入れさせるページを見たことがあると思います。これを「Basic認証」と呼びます。ブラウザーによって認証画面が異なります。

Internet Explorer 7 の場合

Internet Explorer 7 の場合

Firefox 3.0 の場合

Firefox 3.0 の場合

Opera 9.5 の場合

Opera 9.5 の場合

実際に、お使いのブラウザーではどのような画面がでるかを、こちらでお試しください。

このBasic認証は、「.htaccess」と「.htpasswd」いうファイルに記述すれば実現することができます。特に指定がなければ「.htaccess」をおいたディレクトリ配下のすべてのコンテンツに対して制限がかかります。

記述例

AuthUserFile /home/futomi/.htpasswd
AuthGroupFile /dev/null
AuthName "Secret Area"
AuthType Basic

require valid-user

<Files ~ "^.(htpasswd|htaccess)$">
    deny from all
</Files>

太字の行について説明します。この部分を環境に合わせて書き換えなければいけません。その他の行については、そのまま書き加えてください。

AuthUserFile

パスワードファイルの指定です。ここでの指定は、サーバのルートディレクトリからのフルパスで記述しなければいけません。

AuthName

Basic 認証をかける領域名の指定です。上の図の例では、「Secret Area」の部分です。"(ダブルクォーテーション)」で囲まれた部分は、自由に書き換えてください。ただし、「"(ダブルクォーテーション)」は入れないでください。

Files

これは、なくても問題ありません。ただし、「.htaccess」や「.htpasswd」はやはり見せたくありません。そのために、この記述を加えることをお勧めします。

.htpasswdの作り方

記述例

taro:FeNpx1.147CVA
hanako:X6ntcZ021IxMw

.htpasswd に記載される情報は、アカウント名とパスワードです。アカウント名とパスワードは「:(コロン)」で区切られます。複数のアカウントを指定する場合には、改行をして次の行に記述します。パスワードについては、暗号化された状態で保存される必要があります。暗号化は、何かしらツールが必要なのですが、ここでは、パスワードを入れたら、暗号化された文字列を出力するCGI作ってみましょう。

パスワードを入れてください  

パスワードの暗号化は、UNIXのパスワードの暗号化と同じです。この手の内容のホームページでしばしば、"Base64で暗号化" と書いてあるページを見かけたことがありますが、これは間違いです。

ちなみに Base64 は暗号化ではなく符号化です。ブラウザーからサーバへリクエストをする際には、アカウント、パスワードともに、Base64 で符号化されて送信されます。これは HTTP/1.1 で規定されています。

Base64 で符号化された文字は、簡単に元に戻せます。つまり、Base64とは元に戻せるように考案された符号化方式です。しかし、UNIXのパスワードの暗号化は元に戻すために考案されたものではありません。つまり、暗号化された文字列が発見されたとしても、すぐにはパスワードを解析することができないのです。しかし不可能ではありません。したがって、それを防ぐためにも、「.htpasswd」ファイルは、見ることができないようにする必要性があります。

さて、話は元に戻って、Perlでパスワードを暗号化するにはどうしたらいいのでしょう。実は非常に簡単なスクリプトを組むだけで実現できます。

Perlのcrypt関数を使って暗号化します。crypt関数の使い方は、以下のとおりです。

crypt(PLAINTEXT, SALT)

PLAINTEXT の部分は、暗号化したい文字列です。SALT の部分は、大文字・小文字アルファベットと 0 ~ 9 の数字、そして、「.(ドット)」「/(スラッシュ)」のいずれか2文字です。SALT は、暗号化する際のキーとなるもので、PLAINTEXT が文字列でも、SALT を変えることによって暗号化文字列が異なってきます。つまり同じ PLAINTEXT に対して、4096通りの暗号化パスワードが生成しうるわけです。

SALT は、固定で決めてしまってもいいのですが、できる限り複雑にするために、生成するたびにランダムな文字列を指定するのが良いでしょう。いろいろな方法があるかと思いますが、ここでは、rand関数を使ってランダムな2文字を抽出します。

#!/usr/bin/perl
use strict;
use CGI;

my $q = new CGI;
my $pass = $q->param('pass');
my $encpass = &encrypt_passwd($pass);
print "Content-type: text/plain\n\n";
print ${encpass};
exit;

sub encrypt_passwd {
    my($pass)=@_;
    my @salt_set = ('a'..'z','A'..'Z','0'..'9','.','/');
    srand;
    my $idx1 = int(rand(63));
    my $idx2 = int(rand(63));
    my $salt = $salt_set[$idx1] . $salt_set[$idx2];
    return crypt($pass, $salt);
}