ここで正しいユーザ名・パスワードを入力するとファイルを閲覧できます。 間違ったユーザ名・パスワードを入力すると、上記の認証画面が何度でも表示されます。 もしキャンセルボタンを押すと、以下のような画面が表示されます。
% telnet X68000.q-e-d.net 80 GET /~68user/net/sample/http-auth/secret.html HTTP/1.0 (リターン) Host: X68000.q-e-d.net:80 (リターン) (続けてリターン) HTTP/1.1 401 Authorization Required Date: Fri, 03 Dec 2004 15:43:35 GMT Server: Apache/2.0.52 (FreeBSD) WWW-Authenticate: Basic realm="Secret File" Content-Length: 491 Connection: close Content-Type: text/html; charset=iso-8859-1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>401 Authorization Required</title> </head><body> <h1>Authorization Required</h1> <p>This server could not verify that you are authorized to access the document requested. (略)以下の 3点に注目してください。
認証方法にはいくつかの種類があります。例えば Basic 認証と Digest 認証があります (と言っても、それ以外の認証方法を当ページ管理人は知りませんが)。 この例では
WWW-Authenticate: Basic realm="Secret File"というヘッダが示すとおり、サーバ側は Basic 認証を要求しています。
まずユーザ名とパスワードをコロンで結合します。 もしユーザ名「hoge」、パスワード「fuga」の場合、「hoge:fuga」という文字列を作るわけです。 それを BASE64 でエンコードします。 「hoge:fuga」を BASE64 エンコードすると「aG9nZTpmdWdh」となります。
% echo -n 'hoge:fuga' | base64 -e % echo -n 'hoge:fuga' | openssl enc -e -base64 % echo -n 'hoge:fuga' | nkf -MB % echo -n 'hoge:fuga' | perl -MMIME::Base64 -ne 'print encode_base64($_)'参考:「UNIX の部屋」 base64 ・ openssl ・ nkf
上記の Perl の例では MIME::Base64 モジュールを使っていますが、 Perl-5.8 以降であれば標準でインストールされています。 それ以前の Perl であれば適当にインストールしてください。
さきほどのコネクションは既にサーバ側から切断されていますので、 再度 web サーバに接続します。 このとき、
Authorization: Basic (BASE64 エンコードしたユーザ名とパスワード)というヘッダを送ります。
% telnet X68000.q-e-d.net 80 GET /~68user/net/sample/http-auth/secret.html HTTP/1.0 (リターン) Host: X68000.q-e-d.net:80 (リターン) Authorization: Basic aG9nZTpmdWdh (続けてリターン) HTTP/1.1 200 OK Date: Fri, 03 Dec 2004 16:42:56 GMT Server: Apache/2.0.52 (FreeBSD) Content-Length: 176 Content-Type: text/html; charset=euc-jp <html> <head> <META HTTP-EQUIV="Content-Type" Content="text/html; charset=EUC-JP"> <title>ひみつのファイル</title> </head> <body> これは秘密ファイルです。 </body> </html>認証で保護されているファイルを見事に取得できました。
では、誤ったユーザ名・パスワードを送るとどうなるか試しましょう。
% telnet X68000.q-e-d.net 80 GET /~68user/net/sample/http-auth/secret.html HTTP/1.0 (リターン) Host: X68000.q-e-d.net:80 (リターン) Authorization: Basic aaaaa ●誤ったユーザ名・パスワードを送信 (続けてリターン) HTTP/1.1 401 Authorization Required WWW-Authenticate: Basic realm="Secret File" (略) <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>401 Authorization Required</title> </head><body> <h1>Authorization Required</h1> <p>This server could not verify that you are authorized to access the document requested. (略)興味深いことに、Authorization ヘッダを付けないときと全く同じレスポンスが返ってきました。
また、一度 Authorization ヘッダを付けて認証を通った後に、 Authorization ヘッダなしでリクエストを送ってみてください。 やっぱりレスポンスコード 401 が返ってきてしまいます。
つまり、web サーバが行っていることは、
認証が必要なページを取得する場合は、リクエストごとに毎回 Authorization ヘッダを送信する必要があります。HTTP の認証には、ログイン・ログアウトというような概念がないのです。 これはしっかりと認識しておいてください。
#!/usr/local/bin/perl print <<END; Content-type: text/html Status: 401 Authorization Required WWW-Authenticate: Basic realm="Secret File" <html><head><title>401 Authorization Required</title></head> <body><h1>Authorization Required (by CGI)</h1></body></html> END
Authorization: Basic aG9nZTpmdWdhというヘッダは簡単に得られます。これを Base64 デコードすれば「hoge:fuga」が手に入ります。 セキュリティもへったくれもないですね。
<Files ~ "^\.ht"> Order allow,deny Deny from all </Files>
% htpasswd -c .htpasswd hoge New password: (fuga と入力) Re-type new password: (fuga と入力) Adding password for user hoge
ご意見・ご指摘は Twitter: @68user までお願いします。