Digest認証とセッション認証を組み合わせた認証の提案
本稿では, Digest認証, およびセッション認証の欠点を互いに補うあう, 二つを組み合わせた認証方法を提案する.
まず, Digest認証とセッション認証について簡単に説明したのち, 本題に入る.
Digest認証
Digest認証は, HTTPの認証の一つで, Webサーバはユーザのブラウザと資格情報(ユーザ名, パスワードなど)をやり取りする[1].
Digest認証は, ユーザ名とパスワードをハッシュ化してから, ネットワークに流す. 一方, 別のHTTP認証であるBasic認証は, ハッシュ化の代わりに簡単に複合可能なBase64変換を使うため, TLSと組み合わせない限りセキュア(安全)ではない.
Digest認証の一般的な手続き[1]は以下のとおりである.
- クライアントは, 認証が必要なページにアクセスする.
- Webサーバは, 401 "Unauthorized" ステータスとともに,
authentication realm
, ランダムな文字列nonce
を返す. - (ブラウザにユーザ名とパスワードの情報が無いとき)ブラウザは, ユーザに
authentication realm
を提示し, ユーザ名とパスワードの入力を求める.ここで, ユーザはキャンセルできる. - クライアントは, レスポンスコードを含めた認証ヘッダを加えて同じリクエストをWebサーバに送る.
- Webサーバは認証を認め, ページを返す. もしユーザ名, パスワードが異なる場合, サーバは401を返し, クライアントは, 再びユーザに入力を求める.

特徴
- 資格情報のやり取りでユーザ名とパスワードはハッシュ化される(平文ではない)
- 一度認証されると, ブラウザは自動で認証ヘッダを送信するため, ログアウト機能はない[2]
セッション認証
セッションベースの認証は, ユーザのログイン状態をサーバに保存する認証方法の一つである[3]. セッションベースの認証では, ユーザがログインしたときにサーバがセッションデータを作成し保存する. その次にセッションIDをユーザのブラウザにクッキーとして保存する. そのあとの処理で, ブラウザがセッションIDをサーバに送り, サーバはそれとセッションデータを照らし合わせて, ユーザのログイン状態を把握する.
セッション認証の一般的な手続き[3]は以下のとおりである.
- クライアントは, ユーザ名とパスワードを送信
- サーバはセッションデータを作成し保存後, セッションIDをブラウザのクッキーに送信
- クライアントはセッションIDを含めて認証が必要なページにアクセス
- サーバはセッションIDとセッションデータを照らし合わせる
- セッションデータからユーザがログイン状態であるとき, サーバはページを送信

特徴
- ログイン/ログアウト機能がある. ログアウトはセッションの破棄で可能
- ログイン後は, セッションIDでログイン状態を判定するので, クライアントは, アクセス権が必要なページごとに資格情報を送る必要なし.
- フォーム入力によりユーザ名・パスワードを送信するため, クライアント側でユーザ名とパスワードを暗号化していないときや, 通信路が暗号化されていない(TLSではない)ときは安全ではない.
提案手法
本提案手法は, Digest認証とセッション認証の欠点を互いに補い合う方法である.
Digest認証およびセッション認証の利点と欠点は次のとおりである.
- Digest認証
- ✅利点
- 資格情報のやり取りでユーザ名とパスワードはハッシュ化される(平文ではない)
- ❌欠点
- ログアウト機能はない
- 認証が必要なページごとに資格情報を送る必要あり
- セッション認証
- ✅利点
- ログイン/ログアウト機能 あり
- 認証が必要なページごとに資格情報を送る必要なし
- ❌欠点
- 単純なフォーム認証の場合, ユーザ名・パスワードが平文でネットワークに流れる
二つの欠点を補いあい, 本提案手法の利点は次のとおりである.
- 提案手法
- ✅利点
- 資格情報のやり取りでユーザ名とパスワードはハッシュ化される(平文ではない)
- ログイン/ログアウト機能 あり
- 認証が必要なページごとに資格情報を送る必要なし
本手法が適している状況
本手法が向いていると思われる状況は,
- TLSを使用できない環境で, ある程度セキュリティを確保しつつユーザ管理を持ったウェブアプリを作りたい状況[注 1]
です.
フリーのレンタルサーバを使ってTLSを使用できない状況でちょっと凝ったウェブアプリ・ウェブシステムを作りたい方などに当てはまるかもしれません.
認証手続き
- サーバはログインページを送信
- ユーザがログインURLをクリック
- サーバは, 401ステータスとともに有効期限付きのnonceとrealmを返す
- ブラウザは, realmを表示し, ユーザにユーザ名とパスワードの入力を求めたのち, サーバに送信
- サーバは, ユーザ名とパスワードを検証し, 成功したとき, nonceを破棄し, セッションデータを作成, セッションIDをブラウザのクッキーに送信
- クライアントはセッションIDを含めて認証が必要なページにアクセス
- サーバはセッションIDとセッションデータを照らし合わせる
- セッションデータからユーザがログイン状態であるとき, サーバはページを送信

digest認証でのログアウトについて
一般的に, digest認証では認証状態(ログイン・ログアウト状態)をブラウザ側が持っています[1][2]. なので, サーバ側がログアウトをブラウザに強制することはできません. そこで, 先行手法では, 「ダミーのユーザ名で再認証を促す[4]」といった方法があります. ですが, この方法では, 一部のブラウザ(firefoxなど)で警告が表示される場合があり, ユーザに不信感を与えかねません.
本提案方法では, 一度限りの認証のみ有効な制限時間付きのnonce
を用意することで対応させています. 本手法では, 認証が必要な時に制限時間付きのnonce
を発行し, ブラウザに資格情報を送らせます. ブラウザからの応答が遅く制限時間を超えると発行したnonce
は無効化されます. また, 制限時間内に資格情報を送り検証に成功した場合でも, 発行したnonce
を無効化します.
一度限りのnonce
のおかげで, ブラウザに再認証を促すことが可能です. 多くのブラウザでは, nonce
を使いまわして再認証する手間を省きますが, 本手法ではそれができません. ブラウザは認証ページで必ずサーバから401ステータスをもらって再びユーザにユーザ名とパスワードを入力してもらう必要があります[注 2].
認証が必要なページごとに再認証が求められるわけではなく, 求められるのはログイン時のみです. 本手法では一度認証に成功(ログイン)すると, それ以降はdigest認証ではなくセッションベースの認証を行います.
ログアウトでは, セッションベースの認証と同じくセッションの破棄を行います.
実装
本手法「Digest認証とセッション認証を組み合わせた認証方法」は, 2020-8-20時点でContentsPlanetというコンテンツ管理システム(CMS) で使用されています. ContentsPlanet は, TLSを利用できない環境を想定して作られています.
本手法が実装されたスクリプトは以下のようになっています.
Authenticator.php
https://github.com/ContentsViewer/ContentsPlanet/blob/master/Module/Authenticator.php
- digest認証での検証処理
- セッションベース認証での検証処理
CacheManager.php
https://github.com/ContentsViewer/ContentsPlanet/blob/master/Module/CacheManager.php
- 一時的に
nonce
を記録したりする
- 一時的に
index.php
https://github.com/ContentsViewer/ContentsPlanet/blob/master/index.php
- フロントページの窓口
- ここで, 認証が必要か確認する
- 再認証が必要な時は,
403ページ
へとぶ
403.php
https://github.com/ContentsViewer/ContentsPlanet/blob/master/Frontend/403.php
- 再認証を促すページ
- ここに, ログイン画面へのリンクがある
login.php
https://github.com/ContentsViewer/ContentsPlanet/blob/master/Frontend/login.php
- ログインページ
logout.php
https://github.com/ContentsViewer/ContentsPlanet/blob/master/Frontend/logout.php
- ログアウトページ
- セッションの破棄を行う
注釈
参考文献
- ^ a b c "Digest access authentication". Wikipedia. (accessed at 2020-2-18)
- ^ a b "ログアウト機能の目的と実現方法". 徳丸浩の日記. (accessed at 2020-2-19)
- ^ a b "What really is the difference between session and token based authentication". Brian Iyoha. (accessed at 2020-2-22)
- ^ "PHPによる簡単なログイン認証いろいろ". Qitta. (accessed at 2020-3-1)