目次 このページのソースコードを表示

Digest認証とセッション認証を組み合わせた認証の提案

公開日:
更新日:

本稿では, Digest認証, およびセッション認証の欠点を互いに補うあう, 二つを組み合わせた認証方法を提案する.

まず, Digest認証とセッション認証について簡単に説明したのち, 本題に入る.

Digest認証

Digest認証は, HTTPの認証の一つで, Webサーバはユーザのブラウザと資格情報(ユーザ名, パスワードなど)をやり取りする[1].

Digest認証は, ユーザ名とパスワードをハッシュ化してから, ネットワークに流す. 一方, 別のHTTP認証であるBasic認証は, ハッシュ化の代わりに簡単に複合可能なBase64変換を使うため, TLSと組み合わせない限りセキュア(安全)ではない.

Digest認証の一般的な手続き[1]は以下のとおりである.

  1. クライアントは, 認証が必要なページにアクセスする.
  2. Webサーバは, 401 "Unauthorized" ステータスとともに, authentication realm, ランダムな文字列nonceを返す.
  3. (ブラウザにユーザ名とパスワードの情報が無いとき)ブラウザは, ユーザにauthentication realmを提示し, ユーザ名とパスワードの入力を求める.ここで, ユーザはキャンセルできる.
  4. クライアントは, レスポンスコードを含めた認証ヘッダを加えて同じリクエストをWebサーバに送る.
  5. Webサーバは認証を認め, ページを返す. もしユーザ名, パスワードが異なる場合, サーバは401を返し, クライアントは, 再びユーザに入力を求める.
ダイジェスト認証手続き
ダイジェスト認証手続き

特徴

  • 資格情報のやり取りでユーザ名とパスワードはハッシュ化される(平文ではない)
  • 一度認証されると, ブラウザは自動で認証ヘッダを送信するため, ログアウト機能はない[2]

セッション認証

セッションベースの認証は, ユーザのログイン状態をサーバに保存する認証方法の一つである[3]. セッションベースの認証では, ユーザがログインしたときにサーバがセッションデータを作成し保存する. その次にセッションIDをユーザのブラウザにクッキーとして保存する. そのあとの処理で, ブラウザがセッションIDをサーバに送り, サーバはそれとセッションデータを照らし合わせて, ユーザのログイン状態を把握する.

セッション認証の一般的な手続き[3]は以下のとおりである.

  1. クライアントは, ユーザ名とパスワードを送信
  2. サーバはセッションデータを作成し保存後, セッションIDをブラウザのクッキーに送信
  3. クライアントはセッションIDを含めて認証が必要なページにアクセス
  4. サーバはセッションIDとセッションデータを照らし合わせる
  5. セッションデータからユーザがログイン状態であるとき, サーバはページを送信
セッション認証手続き
セッション認証手続き

特徴

  • ログイン/ログアウト機能がある. ログアウトはセッションの破棄で可能
  • ログイン後は, セッションIDでログイン状態を判定するので, クライアントは, アクセス権が必要なページごとに資格情報を送る必要なし.
  • フォーム入力によりユーザ名・パスワードを送信するため, クライアント側でユーザ名とパスワードを暗号化していないときや, 通信路が暗号化されていない(TLSではない)ときは安全ではない.

提案手法

本提案手法は, Digest認証とセッション認証の欠点を互いに補い合う方法である.

Digest認証およびセッション認証の利点と欠点は次のとおりである.

Digest認証
✅利点
  • 資格情報のやり取りでユーザ名とパスワードはハッシュ化される(平文ではない)
❌欠点
  • ログアウト機能はない
  • 認証が必要なページごとに資格情報を送る必要あり
セッション認証
✅利点
  • ログイン/ログアウト機能 あり
  • 認証が必要なページごとに資格情報を送る必要なし
❌欠点
  • 単純なフォーム認証の場合, ユーザ名・パスワードが平文でネットワークに流れる

二つの欠点を補いあい, 本提案手法の利点は次のとおりである.

提案手法
✅利点
  • 資格情報のやり取りでユーザ名とパスワードはハッシュ化される(平文ではない)
  • ログイン/ログアウト機能 あり
  • 認証が必要なページごとに資格情報を送る必要なし

本手法が適している状況

本手法が向いていると思われる状況は,

  • TLSを使用できない環境で, ある程度セキュリティを確保しつつユーザ管理を持ったウェブアプリを作りたい状況[注 1]

です.

フリーのレンタルサーバを使ってTLSを使用できない状況でちょっと凝ったウェブアプリ・ウェブシステムを作りたい方などに当てはまるかもしれません.

認証手続き

  1. サーバはログインページを送信
  2. ユーザがログインURLをクリック
  3. サーバは, 401ステータスとともに有効期限付きのnonceとrealmを返す
  4. ブラウザは, realmを表示し, ユーザにユーザ名とパスワードの入力を求めたのち, サーバに送信
  5. サーバは, ユーザ名とパスワードを検証し, 成功したとき, nonceを破棄し, セッションデータを作成, セッションIDをブラウザのクッキーに送信
  6. クライアントはセッションIDを含めて認証が必要なページにアクセス
  7. サーバはセッションIDとセッションデータを照らし合わせる
  8. セッションデータからユーザがログイン状態であるとき, サーバはページを送信
Digest認証とセッション認証を組み合わせた認証手続き. セッション認証のユーザ名パスワードの送信部分にDigest認証の方法が用いられている
Digest認証とセッション認証を組み合わせた認証手続き. セッション認証のユーザ名パスワードの送信部分にDigest認証の方法が用いられている

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

  • ログアウトページ
  • セッションの破棄を行う

注釈

  1. ^ かなりニッチです
  2. ^ ブラウザであるsafariはそれでも, 再認証をパスします. あきらめずもう一度トライしているのでしょうか? ただブラウザを一度終了すると再認証を求められます.

参考文献

  1. ^ a b c "Digest access authentication". Wikipedia. (accessed at 2020-2-18)
  2. ^ a b "ログアウト機能の目的と実現方法". 徳丸浩の日記. (accessed at 2020-2-19)
  3. ^ a b "What really is the difference between session and token based authentication". Brian Iyoha. (accessed at 2020-2-22)
  4. ^ "PHPによる簡単なログイン認証いろいろ". Qitta. (accessed at 2020-3-1)
「https://contentsviewer.work/Master/Web/Security/DigestSessionAuthentication/article」から取得