ログイン後、ユーザーが「ログイン中の状態」を保てているのは、サーバーがそのユーザーにセッションIDという識別子を発行し、以後のリクエストでそのIDを確認しているためです。
このセッションIDの扱いを誤ると、パスワードとは無関係に、なりすましログインが成立してしまいます。この記事では、実務で押さえておきたいセッション管理の基本を整理します。
セキュリティ対策を横断的に確認したい方は、 Webアプリの脆弱性・セキュリティ対策まとめ もご覧ください。
HTTPはリクエストごとに独立した通信で、それ自体には「誰がログイン中か」という状態を保持する仕組みがありません。そこでサーバーは、ログイン時にランダムな文字列(セッションID)を発行し、Cookieとしてブラウザに保存させます。
以後のリクエストでは、このCookieに含まれるセッションIDをサーバー側の記録と照合することで、「誰がログイン中か」を判定します。つまり、このセッションIDを知っている人は、そのユーザー本人としてログイン中の状態を利用できてしまうということです。
実際に手を動かして確かめてみましょう。以下のデモは実際の通信を一切発生させません。攻撃者から届いたリンクを開き、ログインし、最後に攻撃者側の画面から同じIDでアクセスできるかまで、一連の流れとして確認できます。
実際の通信は発生しません。攻撃者から届いたリンクを開き、ログインし、最後に攻撃者側の画面から同じIDでアクセスできるかまで確認できます。
攻撃者から、次のようなメッセージが届きました。
(クリックすると、実際に何が起きるかを別画面で確認できます)
攻撃者は、自分が最初から知っている「abc123」を使って、マイページに直接アクセスしてみます。
リンクを開いた時点で、ブラウザにsid=abc123というCookieが設定されました(攻撃者があらかじめ用意した値です)。このままログインしてみましょう。
リンクを開くと、ブラウザ風の画面でログイン操作を体験できます。「再生成なし」の状態でログインすると、ログイン前後でセッションIDが変わらなかったはずです。そのまま「攻撃者がこのIDでマイページを開く」を押すと、攻撃者があなたとしてマイページに入れてしまう様子が確認できます(セッション固定攻撃の成立)。「ログイン時に再生成」に切り替えると、ログインのタイミングで新しいIDが発行され、攻撃者が知っている古いIDではマイページを開けなくなります。
セッション固定攻撃(Session Fixation)は、次のような手順で成立します。
対策はシンプルで、ログイン(権限が変わるタイミング)で必ずセッションIDを再発行し、古いIDを無効化することです。多くのフレームワークには、この再発行を行う機能が標準で用意されています。
セッションIDを保存するCookieには、以下の属性を必ず設定します。
SameSite属性については、 CSRF対策とは?トークン方式の仕組み でも解説しています。CSRFトークンとSameSite属性は、どちらもCookieが絡む攻撃を防ぐという点で密接に関係しています。
HttpOnly・Secure・SameSiteを設定するセッション管理は、ログイン画面そのものと同じくらい重要な防衛ラインです。ログイン時のセッションID再発行とCookieの適切な属性設定という2点を押さえておけば、セッションにまつわる代表的な攻撃の多くを防げます。
自分のアプリのログイン処理で、セッションIDが再発行されているか確認してみてください。