Digest認証のパラメータを眺めた
「鯖からのnonceを含めたハッシュを投げて認証するやつでしょ?」
と思ったら意外と沢山パラメータがあったので、一通り読み解いてみた。
鯖→蔵:WWW-Authenticate ヘッダ
// RFC2617 §3.5 より引用 HTTP/1.1 401 Unauthorized WWW-Authenticate: Digest realm="testrealm@host.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"
realm(必須)
Basic認証同様にパスワードダイアログに表示される説明であると同時に、ハッシュ計算にも用いられる。RFC2617では例として「認証を行うホスト名」や「誰がアクセスできるものなのか」を挙げている。
とはいえ registered_users@gotham.news.com
は違和感があるのだけど。
domain
ドメイン名のことではなく、完全なURIもしくは絶対パスのリスト。ここで指定したURI(かつ同じrealm)なら同じ資格情報が使える、という情報になる。省略された場合はレスポンスを返したサーバー全体として扱うべきとされている。
nonce(必須)
Digest認証の要。少なくとも認証しなおす(HTTP401など)ときには更新すべき。例ではタイムスタンプとETagと秘密鍵を使って生成している。
ワンタイムトークンのようにリクエストごとに更新しても構わない。その場合 Authentication-Info ヘッダで次の nonce を通知することもできる。……とはいえ、静的リソースも含めた全リクエストに対してそれをやるのはパフォーマンスの問題があるほか、パイプライン処理などによる同時リクエストも難しくなる。
リプライ攻撃への対策としては nc (nonce-count) パラメータもある。
opaque
いわゆる「ユーザー定義のデータ」。クライアントが同じ認証領域内のURIにアクセスする際、常にAuthorizationヘッダに付加される。
stale
受け取ったAuthorizationヘッダについて、nonce は無効だがユーザー名・パスワードを含むハッシュは正しいという時にtrueになる。どこかから盗んできたnonceかもしれないし、単にタイムアウトしただけかもしれない。
この場合、クライアントはユーザーに尋ねることなく同じ資格情報と新しいnonceで認証しなおせばよい。(元の資格情報を持っていなければここで脱落する)
algorithm
2015年9月に公開された RFC7616 の時点では MD5(互換性のために残してあるが非推奨)、SHA-256、SHA-512-256 の3種類のアルゴリズムを選択でき、それぞれについて MD5
と MD5-sess
のように2種類のバリエーションがある。
Authorization ヘッダの response は user:realm:password
のハッシュ値(A1)をその他のパラメータと連結してまたハッシュ値を計算するのだが、 <algorithm>-sess
の場合は user:realm:password
のハッシュ値にさらに nonce/cnonce を連結してハッシュしたものをA1として使う。
なお毎回のリクエストの署名には上記のA1ハッシュがあれば平文のパスワード等は不要なので、そこはWebサーバー以外で生成したものを使うこともできる。
qop (qop-options)
auth
と auth-int
のうちどれをサポートするかを示す。auth-int
の場合、リクエストボディもハッシュ計算に使われる。
旧版である RFC2069 との互換性のために optional となっているものの、現在では常に使用すべきとされている。このパラメータが省略された場合は RFC2069 互換で動くため、クライアント側も cnonce や nonce-count を使わない。
蔵→鯖:Authorization ヘッダ
// RFC2617 §3.5 より引用 Authorization: Digest username="Mufasa", realm="testrealm@host.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/dir/index.html", qop=auth, nc=00000001, cnonce="0a4f113b", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41"
username は言わずもがな。realm、nonce、algorithm、opaque、qop は上で説明しちゃったので省略。response の生成方法は RFC 見たほうが早いと思うの。
uri(必須)
リクエストのURIをそっくりそのまま。プロキシが勝手に書き換えないように、ということらしい。
cnonce
クライアント側で生成する nonce。このパラメータを付けることで選択平文攻撃への耐性が上がる。要するに、悪意を持った第三者が鯖になりすまして nonce 等々を制御できたとしても cnonce は予測できないので、パスワードの推測が困難になる。
Do Client Nonces enhance the security of HTTP Digest Auth?
nc (nonce-count)
同じ nonce を使ってリクエストを発行するごとにインクリメントされる値(16進数表記)。これも response の計算に使われる。
同じ nc のリクエストを受け取った際に重複として弾くことを目的としている。ここでサーバー側でインクリメントした値を比較してしまうと、リクエストが並列に行われた場合などの「重複はしていないが順序がまちまち」なケースが失敗してしまう。