Digest認証メモ
Digest認証をPerlで書いてみる私的なメモですよ。
サーバー側で事前に行うべき事
まずはブラウザのパスワード入力プロンプトに出て来る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:もちろん用途が特定realmのDigest認証に限る