Basic 認証

パスワードでページを守ろう ~

ホームページを作る上で、特定の人にだけ見せたいページが出てくるでしょう。 そのようなページでユーザー名とパスワードを入力させる認証ダイアログがポップアップ表示するところを見たことがあると思います。 これを Basic 認証 と呼びます。 ここでは、Basic 認証の仕組みや特徴、.htaccess と .htpasswd の書き方、 そして、.htpasswd に記述するハッシュ化パスワードの生成方法について解説します。

Basic 認証のダイアログ

Basic 認証の認証ダイアログは、ブラウザーによって見た目が異なります。

Chrome の場合
Edge の場合
Safari の場合

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

Basic 認証を試す

Basic 認証の特徴

Basic 認証は、認証の仕組みとしては非常にシンプルなため、手軽に用意できるメリットがある反面、 いくつかのセキュリティ上のデメリットもあります。

  1. ユーザー名とパスワードが平文でネットワーク上に送信されてしまう
  2. 認証後は同じディレクトリ内 にアクセスするたびにユーザー名とパスワードをサーバーに送り付けてしまう
  3. にも関わらず、ログアウトという仕組みがない

通常では漏洩しては困るものが平文で何度もネットワーク上に送信されるのですから、セキュリティという観点から見ると非常に心配になるでしょう。 実際には、認証ダイアログでユーザー名とパスワードを入力してアクセスすると、次のような HTTP リクエストヘッダーがサーバーに送信されます。

GET /lecture/htaccess/secret/ HTTP/1.1
...
Authorization: Basic dGFybzpoaW1pdHN1
...

dGFybzpoaW1pdHN1 ですが、これはユーザー名とパスワードを Base64 でエンコードしたものです。 これをデコードすると次のような結果が得られます。

taro:himitsu

このように、実際にはユーザー名とパスワードが直接的に平文で流れるわけではないのですが、 誰でも復号化できてしまうため、平文で送信されているのと事実上同じと言えます。

このような特性上、Basic 認証を使うなら、通信が暗号化される SSL/TLS で利用すべきでしょう。

.htaccess の書き方

Basic 認証は、.htaccess と .htpasswd いう名前のテキストファイルに必要事項を 記載して、制限を設けたいディレクトリに接地することで実現します。まずは .htaccess の書き方を見てみましょう。

記述例
AuthUserFile /home/futomi/.htpasswd
AuthName "Secret Area"
AuthType Basic
require valid-user

以下、各行について説明します。

AuthUserFile

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

AuthName

Basic 認証をかける領域名の指定です。 以前はここで指定した領域名がベーシック認証ダイアログに表示されていましたが、 近年ではほとんどのブラウザーで表示されなくなりました。 さほど気にする項目ではありませんが、不自然ではない名前を入れておきましょう。 ただし、日本語のようなマルチバイト文字は避けましょう。

AuthType

認証方式を指定します。Basic 認証であれば Basic と記述します。 他にはダイジェスト認証というものありますが、ここでは割愛します。

require

何を許可するのかを指定しますが、通常は .htpasswd に記述した ユーザーを許可しますので、valid-user と指定します。

.htpasswd の作り方

.htpasswd に記載する情報はユーザー名とパスワードです。 ユーザー名とパスワードは「:(コロン)」で区切られます。 複数のユーザーを指定する場合には、改行を入れて次の行に記述します。

記述例
taro:FeNpx1.147CVA
hanako:X6ntcZ021IxMw

パスワードは平文ではなく、所定の方法でハッシュ化しておく必要があります。 暗号化は何かしらツールが必要なのですが、.htpasswd 用にハッシュ化ツールを用意しましたのでご活用ください。 後ほど、これを Perl でどのようにして暗号化するのかについて解説します。

パスワードのハッシュ化は UNIX のパスワードのハッシュ化と同じです。 ハッシュ化とは、ある特定のアルゴリズムで別のデータに変換することなのですが、暗号化とは異なり元に戻す (復号化する) ことはできません。 サーバー側では、平文でブラウザーから送信されてきたパスワードを同じアルゴリズムでハッシュ化し、 それが .htpasswd に記述されたハッシュと一致するかどうかをチェックしています。

こうすることで何がうれしいのかというと、仮にハッシュ化されたパスワードが漏洩したとしても元に戻せませんから安全性が高いということです。 実際には元のパスワードを調べる手法がないわけではありませんが、かなり難しいといえます。

Perl でパスワードをハッシュ化する方法

さて、話は元に戻って、Perl でパスワードをハッシュ化するにはどうしたらいいのでしょう。 実は非常に簡単なスクリプトを組むだけで実現できます。前述のハッシュ化ツールのソースコードも紹介します。

ハッシュ化には、Perl のcrypt 関数を使います。crypt 関数の使い方は、以下のとおりです。

crypt(PLAINTEXT, SALT)

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

SALT は固定で決めてしまってもいいのですが、できる限り複雑にするために、 生成するたびにランダムな文字列を指定するのが良いでしょう。 いろいろな方法があるかと思いますが、前述のハッシュ化ツールでは、rand 関数を使ってランダムな 2 文字を抽出します。 以下は前述のハッシュ化ツールのソースコードです。

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

my $q       = CGI->new;
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 );
}