Hatena::ブログ(Diary)

Yet Another Hackadelic

2008-03-10 机上の空論

Digest認証メモ

Digest認証をPerlで書いてみる私的なメモですよ。

Digest認証とは

  1. Digest認証 - Wikipedia
  2. ダイジェストアクセス認証スキーム

辺りを読めば分かります。説明は割愛。

サーバー側で事前に行うべき事

まずはブラウザのパスワード入力プロンプトに出て来るrealmを決めておく事と、realmに対して

server_secret = MD5(username ":" realm ":" password)

と言った値を予め計算しておけば、生のパスワードを保持する必要が無くなる。*1

前提

チャレンジリクエストのレスポンスヘッダで返ってきたWWW-Authenticateの値
WWW-Authenticate: Digest realm="minnaniha naisyo dayo", qop="auth,auth-int", nonce="Lve2pFLu3BGfqf9E0cG63w==", opaque="IBm3pFLu3BGPDuFF0cG63w==", algorithm="MD5"
Authenticateヘッダを含むリクエストヘッダ
Authorization: Digest username="zigorou", realm="minnaniha naisyo dayo", nonce="Lve2pFLu3BGfqf9E0cG63w==", uri="/", algorithm=MD5, response="e5a68629d6bc8592b1c07f2232f1e644", opaque="IBm3pFLu3BGPDuFF0cG63w==", qop=auth, nc=00000001, cnonce="51812c47b046b04b"
Digest認証の確認

簡単に言えば、clientが計算した結果であるresponseの値がサーバー側で同じ計算した時の結果と同じならOKだよって話です。

その計算方法は、

response = MD5(server_secret ":" ":" nonce ":" nc ":" cnonce ":" qop ":" MD5(http_method ":" uri))

server_secretはさっきの値。他は全て二回目以降のリクエストヘッダにあるAuthenticateヘッダに含まれている値です。

実装

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump qw(dump);
use Digest::MD5;
use MIME::Base64;

my ($user, $realm, $password) = ("zigorou", "minnaniha naisyo dayo", "hogehoge");
my $md5 = Digest::MD5->new;
my @digest = ();

$md5->add(join(":", $user, $realm, $password));
push(@digest, $md5->hexdigest);
$md5->reset;

my ($nonce, $nc, $cnonce, $qop) = ("Lve2pFLu3BGfqf9E0cG63w==", "00000001", "51812c47b046b04b", "auth");
push(@digest, $nonce, $nc, $cnonce, $qop);

$md5->add(join(":", "GET", "/"));
push(@digest, $md5->hexdigest);
$md5->reset;

$md5->add(join(":", @digest));
print dump($md5->hexdigest);

最後にdumpしてるのがresponse値。

参考

  1. no title - ソースコードが参考になった。ほとんどパクリ

*1:もちろん用途が特定realmのDigest認証に限る