Webサイトで、クッキーとセッションを使って、ユーザーがサイトに接続し続ける仕組みを説明した、個人的メモです。
ざっくりとした概念的なメモで、厳密な仕様ではありません。
HTTP通信の問題点
- HTTP通信は1回1回の単発の通信なので、接続を維持し続けることができない
- HTTP通信はユーザー識別の仕組みが無いので、どのユーザーからの接続かを判別することができない
- なので、一連のHTTP通信で、ユーザー接続を維持し続けるには、何かしらの仕組みを実装する必要がある
解決方法
ユーザー認証完了後、サーバー側でユーザー識別子を発行し、ブラウザへのレスポンスで識別子を送り、次回以降ブラウザからサーバーにアクセスする際に、毎回その識別子をサーバーに送ることにより、サーバー側でどのユーザーからのアクセスかがわかるようにする。
そして、その識別子のやり取り方法の1つとして、クッキーを用いる方法がある。
クッキーとは?
ざっくり仕様等箇条書き
- クッキーとは、変数名とその値のペアのデータのこと
- クッキーはサーバー側で設定して、ブラウザにレスポンスとして送る
- 受け取ったクッキーはブラウザに保存される
- ブラウザが再度そのサイトにアクセスする際、保存されているクッキーをサーバーに送る
- ブラウザ側でクッキーに変数を追加したり、既存の変数の値を変更することもできる
- クッキーには有効期限を設定できる
- クッキーの有効範囲を、ドメインやパスで絞ることができる
- クッキーの有効範囲を、ドメインやパスで絞った場合、そのクッキーを、他のドメインやパスのサーバーから見ることはできない
一番単純な実装(セキュリティ的にNG)
- ユーザーがログイン完了した時点で、サーバー側で変数「ユーザーID」、値「ユーザーIDの値」のクッキーを作って返す
- 以降、ブラウザからサーバーにアクセスする際、そのクッキーがサーバーに送られる
- サーバー側では、受け取ったクッキーから「ユーザーID」値を取得して、ユーザーを特定することにより、接続を維持する
一番単純な実装の問題点
- 仕様上、ブラウザ側でクッキーが見れて変更できるので、なりすましができてしまう
一番単純な実装の問題点の解決方法
- サーバー側ではユーザーIDではなく、暗号化されたユーザー識別子をクッキーとしてブラウザーに送る
- この暗号化されたユーザー識別子を、一般的に「セッションID」と呼ぶ
- ブラウザからサーバーにアクセスすると、サーバー側では受け取ったクッキーから「セッションID」を取得して、それから「ユーザーID」を復元してユーザーを特定することにより、接続を維持する
- ユーザー識別子は暗号化されているので、他のユーザーのユーザー識別子を生成してなりすますのは困難
セッションについて
- セッションIDの生成方法はHTTPの仕様として定まっていない。サーバー側の実装に依存する
- 各プログラム言語にはメジャーなセッションライブラリがあり、セッションID生成には、それらを使うことが多い
- それらのライブラリの多くのデフォルトの実装は、セッションIDとしてユニークで推測しずらい値を生成し、それをキーとして「ユーザーID」などのユーザーデータを紐付けて、ローカルファイルやメモリ上にキーバリューデータとして保存しておく
- そして、ブラウザーからアクセスがあった場合は、クッキーからセッションIDを読み取り、セッションIDをキーに、キーバリューデータから該当するユーザーデータを復元する
- キーバリューデータをサーバーのローカルファイルやメモリに保存するため、サーバーを複数設置して負荷分散させた場合、接続毎に接続先のサーバーが変わってしまうので、セッションが維持できなくなってしまう
- なので、どのサーバーにアクセスしても適切なユーザーデータが復元できるように、キーバリューデータをローカルではなく、データベースに格納するようにすることも多い
感想など
ユーザー認証するサイトを作る必要がありました。
こういうセキュリティに絡む部分は自分で実装せず、ライブラリに任せてしまうのがいいのですが、ライブラリを使うにしても、概念は知っておいた方がよく、このあたりがよく分かってなかったので、備忘録として自分メモを作りました。
シングルページアプリケーションの場合でも、セッションIDとクッキーが、トークンとAuthヘッダーに代わっただけで、暗号化されたIDから情報を取り出して確認するという、基本的な考え方は同じですね。