はじめに
Laravelのログアウト処理とCSRF対策について、自分用の復習問題としてまとめます。
まず自分の言葉で答えてから、「答えを見る」を開きます。
① セッションと認証
Q1. セッションID・ユーザーID・webガードの役割は?
答えを見る
- セッションID:どのセッションかを特定する
- ユーザーID:どのユーザーかを特定する
- webガード:セッションを使って、誰がログインしているか確認する
ログイン時には、セッションの login_web_* に既存のユーザーIDが保存される。ログインのたびにユーザーIDを作るわけではない。
Q2. HTTPがステートレスなのに、ログイン状態を保持できるのはなぜ?
答えを見る
ブラウザがCookieでセッションIDを送り、サーバーが対応するセッションの認証情報を確認するため。
セッションは複数のリクエストにまたがって使われる、一時的な状態の保存先。
② ログアウト処理
Q3. 次の3つの処理は、それぞれ何をする?
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
答えを見る
-
logout():セッションの認証情報を削除するなどして、認証状態を解除する -
invalidate():セッションのデータをすべて消し、古いセッションIDを破棄して新しいIDを生成する -
regenerateToken():新しいCSRFトークンを生成し、セッションに保存する
users テーブルのユーザー情報は消えない。
Q4. 認証情報を消した後、なぜセッションIDも変更する? 古いIDだけで再ログインできる?
答えを見る
古いIDを、その後のセッションの引換券として使わせないため。
ただし、認証情報が削除されていれば、古いセッションIDだけで再ログインできるわけではない。
新しいIDのCookieは、通常、ログアウト処理後のレスポンスでブラウザに渡される。
③ CSRF対策
Q5. CSRFはどんな攻撃で、トークンは何のためにある?
答えを見る
CSRFは、本人のブラウザに意図しないリクエストを送らせる攻撃。
Cookieが自動で送られる状況を悪用する。
CSRFトークンはセッションごとの合言葉。送信された値とセッション内の値を照合し、外部サイトからの勝手な送信を防ぐ。
本人の意思や、操作する権限まで保証するものではない。
Q6. CSRFトークンはどこにあり、なぜ攻撃者のサイトからは読み取れない?
答えを見る
- サーバー側:セッションの
_token - ブラウザ側:通常のフォームでは、
@csrfが生成する隠し入力欄
<input type="hidden" name="_token" value="abc123">
ブラウザの同一オリジンポリシーにより、攻撃者のサイトは通常、正規ページの中身を読み取れない。
隠し入力欄だから秘密になるわけではない。
Q7. ログアウト前のフォームを、そのまま送信した場合と、リロードしてから送信した場合の違いは?
答えを見る
ログアウト時にトークンを更新していれば、古いフォームをそのまま送ると不一致になり、通常は419エラーになる。
リロードしてフォームを新しく取得すると、現在のセッションのトークンが埋め込まれる。
リロードのたびにトークン自体が新しく生成されるわけではない。また、CSRFチェックを通過しても、ログイン状態や操作権限は別途確認される。
まとめ
- セッションIDはセッションを、ユーザーIDはユーザーを特定する
- ログアウト時は、認証解除・セッションのリセット・CSRFトークンの再生成を行う
- CSRFトークンは、意図しない送信を防ぐためのセッションごとの合言葉