クッキーとセッションを雰囲気で使っているエンジニアが、違いを説明できるようになる記事
どうもお疲れ様です。MESIです。
Web系のエンジニアをやっていると普段からクッキーやらセッションやらを使うことになると思います。
皆さんの職場でも、こんな言葉を耳にするのではないでしょうか。
- 「クッキーに保存しよう」
- 「クッキー削除しよう」
- 「セッションに保存しよう」
- 「セッションが切れた」
そこで私のようなよわよわエンジニアはこう思うのです。
「クッキーとセッションの違い is 何?」
今回はそんな私のようなエンジニア向きにクッキーとセッションを説明していきます。
そもそもなぜクッキーやらセッションが必要なのか
そもそもなぜクッキーやセッションは必要なのでしょうか。
それはHTTPはステートレスなプロトコルだからです。
ステートレスって?
ステートレスは、その名の通り「状態を保持しない」ことを指します。
HTTPはサーバーがクライアントの状態を覚えず、毎回新たなリクエストとして処理される仕組みです。
例えばあなたがハンバーガーショップに出向いたとします。
すると通常では以下のようなステートフルなやりとりが行われます。
ステートフルなので店(サーバー)は客(クライアント)直前の状態を覚えています。
客「ハンバーガーセットをください。」
店「サイドメニューは何になさいますか?」
客「ポテトで。」
店「ドリンクは何にしますか?」
客「コーラで。」
一方でもしステートレスなやり取りが行われたらこのようになります。
客「ハンバーガーセットをください。」
店「サイドメニューは何になさいますか?」
客「ハンバーガーセットをポテトでお願いします。」
店「ドリンクは何にしますか?」
客「ハンバーガーセットをポテトとコーラでお願いします。」
このようにステートフルなやりとりではサーバ(店)がクライアント(客)のそれまでの注文を覚えているのに対してステートレスなやりとりではクライアント(客)は毎回すべての注文を繰り返していますね。
これがステートレスです。
しかしこれではECサイトのような客が何をカートに入れたか覚えていないといけないステートフルが要求されるサイトでは困ってしまいますね。
そこでクッキーを利用する
HTTPがステートレスなプロトコルであるため、サーバーはクライアントの状態を覚えておく仕組みがありません。そこでクッキーを利用することで、状態(ユーザーが誰で、どんな操作をしているか)をやり取りできるようにします。
クッキーはサーバーからクライアント(ブラウザ)に「この情報を保存しておいてね」という形で送られ、次回以降ブラウザからサーバーに自動で送信される小さなテキストデータです。
例えば、あなたがネットショップを利用するときに「カートにハンバーガーを入れた」ことをサーバーは覚えられません。そこでクッキーに
cart=hamburger
のような名前=値
の組み合わせで構成されたデータを書いておいてもらい、次にページを読み込むとき「このブラウザはcart=hamburgerというクッキーを持っているから、ハンバーガーをカートに入れている人だな」とサーバー側が判断できます。
こうすることで、サーバーは「さっきハンバーガーを注文しかけていた人だな」「カートに何が入っているのかな」と認識できるようになります。
クッキーの危険性について
これまで学んだクッキーを使うことでログインを実現することができます。
例えばクッキーに
userID=1000
という情報を入れてブラウザに保存してあげれば、サーバーはこのクッキーを利用して「ユーザーID=1000」の人がリクエストしてきたと判断できます。
しかし問題は、クッキーの内容はユーザー側で自由に書き換えられてしまう可能性がある点です。
もしもクッキーを
userID=1001
のように編集され、実際にuserIDが1001のユーザーが存在していれば、なりすましログインされる危険があります。
このように他人のセッションに侵入する攻撃を、「セッションハイジャック」と呼びます。
また、クッキーはデフォルトでは平文で保存されるため、HTTPSで暗号化されていない通信経路では盗聴・改ざんが容易に行われる恐れがあります。
そこでセッションを使う
クッキーにユーザーのIDなどをそのまま保存してしまうと、書き換えられたり盗聴されたりしてセッションハイジャックにつながる恐れがあるという問題がありました。
しかし「ユーザーを識別してステートフルなやり取りをしたい」ニーズは依然としてありますよね。
そこで登場するのが「セッション」です。
セッションの仕組み
セッションはクッキーを応用した仕組みで、クッキーとまったく無関係なわけではありません。
生のユーザー情報やカート情報などを直接クッキーに保存する代わりに、サーバー側で管理したデータにひも付くセッションIDのみをクッキーに保持させる、という方法を取ります。
サーバー内ではユーザーIDやカートの中身などの機密情報を、メモリ・データベース・Redisなどに保存し、セッションIDと照合する仕組みです。
クライアントにはセッションIDだけを渡す
クッキーに保存するのは「セッションID」のみです。
具体的には以下のようなランダムかつ推測されにくい文字列が、クッキーとしてブラウザに保存されます。
sessionID=abc123XYZ987
サーバー側でセッション情報を管理する
たとえば「ユーザーID」「カートの中身」「ログインしているかどうか」など、重要なデータはすべてサーバー側で保持します。
これらのデータはサーバー内のメモリやデータベース、Redisなどのセッションストアに保存されることが多いです。
実際の機密情報はサーバー側に置く
ユーザーがログインしているかどうかや、カートの中身などの「第三者に知られたくない情報」は、ブラウザには置かずサーバー側に保管しておきます。
ユーザーがブラウザでクッキーを書き換えようとしても、そこに書かれているのは「セッションID」だけです。
もしセッションIDが推測不能なランダム文字列なら、そう簡単には別のユーザーのセッションIDを作り出すことはできません。
セッションのメリット
直接的な改ざんが難しい
クッキーに「userID=1000」のようにIDを直書きしていると書き換えられてしまうかもしれませんが、セッションIDだけなら意味がありませんね(ただのランダム文字列なので)。
たとえユーザーが勝手にクッキーのセッションIDを書き換えても、サーバー側のセッションストアと紐付かない限り正しいデータは得られません。
機密情報を安全に管理できる
クッキーでやりとりされるのは「セッションID」のみなので、パスワードなど、直接的に見られたくないデータはすべてサーバー側で管理できます。
ログアウトやタイムアウトを実装しやすい
「一定時間操作がなかったらセッションを破棄する」などの仕組みをサーバー側で集中管理できるため、ログアウトやセキュリティ制限を柔軟に運用できます。
セッションの注意点
セッションIDの盗難リスク
もしセッションIDそのものが漏れてしまうと、結局はそのIDでサーバーを騙すことが可能になり、なりすましされる危険があります(セッションハイジャック)。
対策としては以下のものがあります。
- HTTPS(TLS)で通信を暗号化する
- Secure フラグや HttpOnly フラグを付ける
- アクセス元IPアドレスのチェックやワンタイムトークン(CSRF対策)など、追加のセキュリティ機構を取り入れる
サーバー負荷・スケーリングの問題
セッションを多くのユーザーが利用すると、サーバー側でそれだけ多くのセッション情報を管理しなくてはなりません。
サーバーの台数を増やして負荷分散する場合には「セッションの同期」をどうするかが課題になります(たとえば Redis やデータベースをセッションストアにして集中管理する、Sticky Session を使うなど)。
まとめ
1. HTTPはステートレス
- サーバーはリクエストごとに「誰が何をしているか」を覚えていない
2. クッキーで状態を擬似的に保持
- サーバーが「クッキーを保存しておいて」と言えば、次回以降のリクエスト時にそのクッキー情報でユーザーを識別できる
- 名前=値 の形式でブラウザに保持する
3. クッキーの改ざんや盗聴リスク
- クッキーをそのまま使うと、書き換えによる不正ログインや通信経路上の盗聴が怖い
4. セッションを導入して機密情報はサーバー側で管理
- クライアント側は「セッションID」だけ
- サーバー側でユーザーの重要データを集中管理し、改ざんを防ぐ
クッキーとセッションの違い
項目 | Cookie | Session |
---|---|---|
データ保存場所 | ユーザーのブラウザ | サーバー側ストア (メモリ/DB/Redisなど) |
具体的な中身 | ユーザーIDなど任意の情報を直書き可 | セッションIDのみ(中身はサーバー内に保持) |
セキュリティ面 | 平文で書き換え可能, 窃取されやすい | IDの盗難リスクはあるが改ざんされにくい |
負荷のかかり方 | サーバー負荷は少なめ | 多数のセッションをサーバーが管理し負荷大 |
「クッキーとセッションの違い is 何?」と疑問に思っていた方も、これでだいぶイメージが湧いたのではないでしょうか。
セッションはクッキーの弱点を補うための仕組みですが、セッションIDが盗まれるリスクもゼロにはなりません。
ぜひ今回の内容を踏まえ、「どこに」「どんな情報を」「どのように保存するか」を常に意識して、安全で使いやすいWebアプリケーションを作ってみてください!
Discussion
初見で、どうしても
という疑問が出そうだなという感想を持ってしまいました。
この手の解説をする際は、実現したいこととやり方、それを支える技術といった整理をしたうえで比較対象などを検討するのが良いと思います。
あと、RFCやW3Cなど標準化されているものについては、なるべくその参照を示す方が良いでしょう。
厳密な定義を調べることで、アプリケーションの動作の中でどの部分の処理についての仕様なのかが明確になり、今回のような比較を用いた記事も書きやすくなるでしょう。
そこまで示すの、この記事の本筋とはそれると思います。
そこまで読みたいなら、他の記事を参照するのがいいと思う。
これはセッションハイジャックというよりも なりすましログイン な気も……?(「セッションを使う」の前な為