目次
1. Digest認証とは?
本記事では、HTTP認証(HTTP というプロトコルを利用した認証)の1つである Digest認証の設定手順について説明します。
HTTP認証の中で一番有名(?)な Basic認証 と同じくらい手軽に設定でき、且つセキュリティ的により安全なのが Digest認証です。
Basic認証では入力したパスワードが平文でサーバーに送信される(そのため HTTPSで利用することが必須)のに対して、Digest認証では「ランダムな文字列(チャレンジ) + パスワード」がハッシュ化(分かりにくい文字列に変換される)されて送信されます(*1)。これは、チャレンジ・レスポンス方式と呼ばれます。
(*1) 実際はもう少し複雑です。詳細は RFC 2617 を参照してください。
2. Webサーバーの対応
Apache では Digest認証が使えますが、nginx だと標準では対応していないようです。
Webで簡単に認証を掛けたい場合は、Basic認証 + HTTPS で良いという考えなのかもしれません。
3. Digest認証の設定手順
ここでは Apache 2.4 (on CentOS 7) での手順について説明します。
(1) Digest認証が使えるか確認する
Digest認証を行うには、Apache にDigest認証のモジュールが読み込まれている必要があります。以下のコマンドで確認します(環境によっては、管理者権限が必要かもしれません)。
$ sudo httpd -M | grep digest
実際に実行した例が以下です。
$ sudo httpd -M | grep digest
auth_digest_module (shared)
auth_digest_module
というモジュールが読み込まれていることが分かります。
もし何も表示されない場合は、Apache の設定ファイルに、Digest認証モジュールを読み込むための設定を追記する必要があります。その後、Apache を再起動してください。
LoadModule auth_digest_module modules/mod_auth_digest.so
参考
(2) Digest認証のファイルを作成する
Digest認証で使用するユーザー名・パスワード・realm(領域) を記録しておくファイルを作成します。
以下のコマンドで作成します。
$ sudo htdigest -c {ファイルパス} '{領域名}' {ユーザー名}
- {領域名} はスペースを含むことも多いだろうということで、シングルクォーテーションで囲っています。
- 参考:htdigest – manage user files for digest authentication – Apache HTTP Server Version 2.4
実行例が以下です。
$ sudo htdigest -c .digestpass 'Digest Auth' foo
実行すると、パスワードを聞いてきますので入力します。
このとき、生成された .digestpass ファイルの内容は例えば以下のようになっています。
$ cat .digestpass
foo:Digest Auth:cce31c0fdaf4d98cdda656f24b7baf4c
(3) Apache の設定ファイルに認証するための記述を行う
ここでは、特定のディレクトリに対して Digest認証を掛ける場合を想定し、そのディレクトリ直下の .htaccess
ファイルに設定を記述します。
記述する内容は以下です。
AuthType Digest
AuthName "{認証名}"
AuthUserFile "{認証情報のファイルパス}"
Require valid-user
AuthType
とRequire
は上記のまま記述します。AuthName
とAuthUserFile
は、自分が決めた内容を記述します。
一例を示します。
AuthType Digest
AuthName "Digest Auth"
AuthUserFile "/path/to/.digestpass"
Require valid-user
.htaccess
への記述のため、Apache を再起動する必要はありません。
以上の設定を行うと、Digest認証が有効になります。
4. Digest認証でのやり取り
Digest認証でのウェブブラウザとウェブサーバーとのやり取りを抜粋して記載します。
(1) Digest認証が設定されたURLにウェブブラウザでアクセスすると、HTTPステータスコード 401 (Unauthorized) が返され、ウェブブラウザはユーザー名とパスワードの入力を促します。
このとき、ウェブサーバーからウェブブラウザに返されるされる HTTPヘッダには、www-authenticate
というフィールドが含まれます。そのフィールドの例を以下に示します(読みやすくするため改行しています)。
www-authenticate:
Digest
realm="Digest Auth",
nonce="lamPKUShBQA=98cbd2bcb9d1099195eb65fb1c514fe2b55bc5a3",
algorithm=MD5,
qop="auth"
(2) ユーザー名とパスワードを入力してログインボタンを押します。
このとき、ウェブブラウザからウェブサーバーに送信される HTTPヘッダには authorization
というフィールドが含まれます。そのフィールドの例を以下に示します(読みやすくするため改行しています)。
authorization:
Digest
username="foo",
realm="Digest Auth",
nonce="lamPKUShBQA=98cbd2bcb9d1099195eb65fb1c514fe2b55bc5a3",
uri="/web-test/003/",
algorithm=MD5,
response="6ff30b800cf53ba5ba31651ed5da71d5",
qop=auth,
nc=00000002,
cnonce="47fc00956aae926c"
この中の response
は、パスワード文字列やその他の情報をハッシュ化した文字列がセットされています。
この情報を受け取ったウェブサーバーは、同じやり方で文字列を生成し、response
と一致するかを検証します。一致すればログイン成功です。
5. Digest認証の response を計算してみる
以下の authorization
フィールドに記載された response
以外の値を元にして、 response
に記述されている文字列を自分で生成してみましょう。
※ HTTPメソッドは GET であり、パスワードは password であることは分かっているとします。
authorization:
Digest
username="foo",
realm="Digest Auth",
nonce="lamPKUShBQA=98cbd2bcb9d1099195eb65fb1c514fe2b55bc5a3",
uri="/web-test/003/",
algorithm=MD5,
response="6ff30b800cf53ba5ba31651ed5da71d5",
qop=auth,
nc=00000002,
cnonce="47fc00956aae926c"
RFC 2617 に文字列の算出手順が書いてあるのですが、今回使う部分のみを以下に抜粋します。上記のフィールドに出ている項目名がそのまま使われているので、どこにどの値を入れればよいのかはおおよそ検討が付くと思います。詳細はリンク先を参照してください。
A1 = unq(username-value) ":" unq(realm-value) ":" passwd
A2 = Method ":" digest-uri-value
H(data) = MD5(data)
KD(secret, data) = H(concat(secret, ":", data))
request-digest = <"> < KD ( H(A1), unq(nonce-value)
":" nc-value
":" unq(cnonce-value)
":" unq(qop-value)
":" H(A2)
) <">
ここに出てくる A1
, A2
を元に H(A1)
, H(A2)
を算出し、最後に request-digest
を算出します。この request-digest
が response
に一致するはずです。
実際やってみると、A1
, A2
, H(A1)
, H(A2)
は以下となります。
A1 = foo:Digest Auth:password
A2 = GET:/web-test/003/
H(A1) = cce31c0fdaf4d98cdda656f24b7baf4c
H(A2) = 157fb7b768228837518320d7e8abac99
詳細は省きますが、request-digest
は cce31c0fdaf4d98cdda656f24b7baf4c:lamPKUShBQA=98cbd2bcb9d1099195eb65fb1c514fe2b55bc5a3:00000002:47fc00956aae926c:auth:157fb7b768228837518320d7e8abac99
の MD5 ハッシュ値となり、実際にやってみると 6ff30b800cf53ba5ba31651ed5da71d5
を得ることができました。
※ MD5 のハッシュ値を得るのに、エンコード/デコード/ハッシュ – Tools on Web を使いました。
6. その他のメモ
- 一度 Digest認証で認証を通ってしまうと、ブラウザを閉じるまでその情報を覚えています。何度も認証を試したい場合は、シークレットウィンドウ (Chrome) の利用をお勧めします。
7. おわりに
正直 Digest認証はあまり使われていない印象です。レンタルサーバーなどでもアクセス制限機能と称して Basic認証が使われていたりします。最初の方でも書きましたが、HTTPS さえ使っていれば Basic認証で問題ないのかもしれません。なんだが残念です。