🍪

キャッシュ・クッキー・セッションの違い

2024/10/11に公開

はじめに

インターン先でWEBアプリのログイン画面作成を任された際に、疑問に思ったことを調べたのでここでアウトプットします!
(もし理解が間違っていれば指摘して頂けると嬉しいです!)

今まであまり意識せずにセッションやクッキーといった言葉を使ってきましたが、いまいち違いが分かっていないな。と思ったので自分なりに調べました!
調べていく中でキャッシュという言葉も登場してきたので、キャッシュも含めた3つの言葉についてまとめています!

クッキー(cookie)について

ユーザのブラウザに保存する約4KBのテキストファイルのこと。

役割

サーバ側がユーザを認識し、過去にそのサイトを訪れたことがある人なら、その個人それぞれに対しての特別な対応をするため。
自動ログインやユーザが過去に閲覧したページの管理など。

保存場所

ユーザーのブラウザ

有効期間

※2種類のクッキーがあり、それぞれのクッキーで異なる。

  • セッションクッキー
    ユーザがブラウザを閉じると消滅する!
  • 永続クッキー
    サーバが永続クッキーをブラウザに作成する際に、有効期限を設定できる。
    有効期限を2週間とすると、二週間後に自動的にブラウザから削除される。

具体的なクッキーの流れ(セッション管理)

ブラウザ(クッキー)側

➊ユーザがアクセスした際にサーバがsessionID[1]を発行し、そのsessionIDをクッキーに保存。
その他の情報もクッキーに保存できる。
ただし、クッキー内の情報は改ざんや盗み見されるリスクがあるので、重要な情報は保存するべきではない。
重要な情報をクッキーに保存する際は、HttpOnly(JavaScriptからのアクセスを禁止)や Secure(HTTPSでのみ送信)を設定して、暗号化した通信のみで送受信されるようにすべき。

サーバ側(以前にこのサイトを訪れたことがあるユーザーが再び訪問した場合)

➍ユーザのクッキーからsessionIDを取得し、そのsessionIDが有効かどうかを確認。
有効かどうか確認する方法は、ユーザのクッキーに格納されていたsessionIDがサーバに保存されている「有効なsessionIDリストのようなもの」に存在するかどうかを確認する。
有効か無効かで、そのユーザに対する処理を変えられる。
sessionIDに基づいて、ユーザの情報をサーバに保存することもできる。
(サーバ側に保存するので容量はほぼ無制限)

アプリサーバを複数稼働させる場合(インターン先の大先輩より)

以下イラストのようにバックエンド側のアプリサーバを複数台稼働させた場合、アクセス先のアプリサーバが変わると、セッション管理できなくなる。

具体的に言うと、このような問題が発生する。

  1. ユーザAがWEBサーバにアクセスする。(紫色の矢印)
  2. WEBサーバがXのアプリサーバと通信し、sessionIDがXのアプリサーバに保存される。(紫色の矢印)
  3. 一度WEBサーバを離れてから再度ユーザAがWEBサーバにアクセスする。(ピンク色の矢印)
  4. WEBサーバがZのアプリサーバと通信する。(ピンク色の矢印)
  5. しかしZのアプリサーバにはユーザAのsessionIDが存在しないため、セッション管理ができない。

    ※アプリサーバの横にあるクッキーイラストはクッキーを指しているわけではなく、ユーザに保存されたクッキーと関連づいた情報を表している。

解決策➊WEBサーバのパーシステンス機能を用いる

ロードバランサー(LB)[2]の重要な機能の1つに、「パーシステンス」という機能がある。
パーシステンスは、同一のユーザーからのリクエストを常に同じサーバーに転送するセッション維持機能。
この機能により、ユーザーの一連のアクセスを同じサーバーで処理することができる。

ロードバランサーとWEBサーバ、Apache・Nginxの違いもよくわからなかったので別記事にまとめる。

解決策➋同一のデータベースにセッション情報を保存する

下のイラストにあるように、全てのアプリサーバが同一のデータベースにセッション情報を保存する。
データベースには常に全ユーザのセッション情報があり、それをアプリサーバが参照するため、ユーザがどのアプリサーバを割り当てられても、問題なくセッション管理できる。


セッションについて

Webサイト利用中の状態を管理する仕組み。

役割: ログイン状態やショッピングカートの内容を保持する。
管理方法: セッションクッキーを利用。
有効期間: ブラウザを閉じると消える。
用途例: ログイン状態の維持、ショッピングカートの管理。

キャッシュについて

Webサイトの表示速度を向上させるための一時的なデータ保存機能。

役割: Webサイトの表示を高速化する。
保存場所: ユーザーのブラウザ
有効期間: ブラウザの設定や、サイトの指定による(長期間保存可能)。
用途例: HTMLファイル、画像、CSSファイルなどの一時保存。

セッション管理実装してみる

from flask import Flask, request, redirect, url_for, session

app = Flask(__name__)

app.secret_key = 'your_secret_key'  
# セッションを使用するために必要なシークレットキーを設定
# ここの文字数字列をもとに、暗号化を行っている。ハッシュ化みたいな感じ。

# セッションの有効期限を秒単位で設定(ここでは5分 = 300秒)
# これはサーバ側のセッションの有効期限。クッキーの有効期限ではない。
app.permanent_session_lifetime = 300

@app.route('/', methods=['GET', 'POST'])
def index():
    # クッキーを持ってなかったらそもそも何の情報も入っていないからここは実行されない。
    # クッキーを持っていた場合は、sessionの値(暗号化されている)それを復元して、
    # その表の中にusernameがあればログイン済みと判定。
    if 'username' in session:
        return 'あなたはログインしたことがあります!'
    
    # POSTリクエスト(ログイン処理)
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        
        # 簡単なユーザー認証の例(本番ではセキュリティ上もっと複雑なものにすべき)
        if username == 'user' and password == 'pass':
            session['username'] = username  
            # セッションに辞書型の配列のようなものを作成し、
            # キー(username)と値(ユーザが入力したユーザー名)を挿入
            session.permanent = True
            # これをTrueにすることで、永続クッキーとなる。
            return redirect(url_for('index'))
        else:
            return 'ログインに失敗しました。もう一度お試しください。'
    
    # GETリクエスト(ログイン画面の表示)
    return '''
        <form method="post">
            ユーザー名: <input type="text" name="username"><br>
            パスワード: <input type="password" name="password"><br>
            <input type="submit" value="ログイン">
        </form>
    '''
    # ↑でmethodがPOSTであると指定している。



@app.route('/logout')
def logout():
    session.pop('username', None)  
    # セッションからusernameというキー、そこに格納された値を削除
    return redirect(url_for('index'))

if __name__ == "__main__":
    app.run(debug=True)

どのようなものか

  • Flaskフレームワークを使用して実装されたシンプルなログイン・ログアウト機能を持つWebアプリケーション。
  • ユーザーがフォームに入力したユーザー名とパスワードをセッションに保存し、ログイン状態を維持する。
  • ログイン状態が維持された状態でアクセスすると、あなたはログインしたことがあります! というメッセージが表示される。
  • ログアウト時には、セッションからユーザー名を削除してログアウト処理を行う。また、セッションには5分の有効期限が設定されている。

処理の流れ

  1. 初回ログイン時にsessionIDを作成。セッションデータ({'username': 'ユーザが入力したusername'})をsessionオブジェクトに保存。セッションデータはサーバ内(DBに保存することも可)に保存される。
  2. サーバーはsessionID+署名をクッキーに保存してクライアントに送信。
    クッキーに値を入れる際に、自動的にキーとしてsessionという名前が付けられる。
  3. クライアントはこのクッキーをブラウザに保存し、次回のリクエスト時に自動的にサーバーに送信。
  4. サーバー側では、受け取ったクッキーの署名を検証し、問題がなければ、格納されたsessionIDと対応するusernameを参照する。
  5. if 'username' in session: でユーザーがログイン済みかどうかを判定する。

サーバ側で情報がどのように保存されているか

以下のようにsessionIDごとに情報が保存されている。
保存されているusernameなどの情報は、青の波線にある.binというファイルに格納されている。
シリアライズ[3]されているみたいで、ファイルを開いても文字化け?していた。

session情報をDBに保存したときのもの(念のためsessionIDは隠している)

最後に

少しはセッション、クッキーについて理解することができたので、これをもとにインターン先のWEBアプリに組み込んでみようと思います!
GoogleFirebaseを用いたログイン機能も簡単に作成できるみたいなので、またよく調べないと。。

冒頭でも申し上げましたが、私の間違いなどございましたら、ご指摘していただけると嬉しいです。
ブログも初心者のため、「この辺りが見にくい」「構成はこうした方が良い」などございましたら、ご教示していただけると幸いです。

最後まで読んでいただき、ありがとうございました!

参考元

脚注
  1. Webサービスにおいてユーザーを一意に識別するために使用される固有のID ↩︎

  2. サーバーにかかる負荷を複数のサーバーに平等に振り分けるための装置 ↩︎

  3. プログラム内のオブジェクトやデータ構造を、ストレージやネットワーク転送に適した形式に変換すること ↩︎

Discussion