Python入門

ざっくり解説!クッキーとセッションの違いとそれぞれの役割について

「ログインしたのに、ページを移動したら情報が消えてしまった…」「Cookieとセッションって何が違うの?」——Flaskを使い始めたばかりのころ、こんな疑問を持ったことはありませんか?

WebアプリではHTTPというプロトコルを使って通信しますが、HTTPはステートレス(状態を持たない)という性質があります。つまり、リクエストのたびに「誰が送ってきたのか」をサーバーは忘れてしまいます。ログイン状態やカートの中身を覚えておくために必要なのが、CookieとSession(セッション)の仕組みです。

この記事では、Cookie・クライアントサイドセッション・サーバーサイドセッションの3つをわかりやすいたとえ話とFlaskの実装コードを交えて解説します。「なんとなく動かせているけど、違いがよくわからない」という方はぜひ最後まで読んでみてください!

🍪 Cookieとは何か?

web security cookie browser
web security cookie browser / Photo by Abdullah Bin Mubarak via Pexels

仕組みと特徴

Cookieとは、サーバーがブラウザに保存させる小さなデータのことです。サーバーがHTTPレスポンスヘッダーに Set-Cookie を含めてブラウザに送ると、ブラウザはそのデータを保存し、次回以降のリクエスト時に自動的にサーバーへ送り返します。

たとえ話でいうと、「鍵付きロッカーに入れた荷物」のイメージです。サーバーが荷物(データ)を用意してロッカーに入れ、あなた(ブラウザ)はその荷物を読んだり、自分で中身を書き換えたりすることもできます。

  • データはブラウザ(クライアント側)に保存される
  • 文字列として中身が見える・書き換えられる(暗号化しない場合)
  • 有効期限(expires)を設定できる
  • ドメイン・パスを指定してスコープを絞れる

具体的なユースケース

  • 「次回もログイン状態を保持する」チェックボックス
  • ECサイトの言語設定・表示設定の保存
  • アクセス解析用のトラッキングID
  • セッションIDの受け渡し(後述)

FlaskでCookieを操作する

from flask import Flask, request, make_response

app = Flask(__name__)

# Cookieをセットするエンドポイント
@app.route('/set_cookie')
def set_cookie():
    resp = make_response('Cookieをセットしました!')
    # max_age=秒数で有効期限を設定
    resp.set_cookie('username', 'taro', max_age=60*60*24)  # 1日間
    return resp

# Cookieを読み取るエンドポイント
@app.route('/get_cookie')
def get_cookie():
    username = request.cookies.get('username', 'ゲスト')
    return f'こんにちは、{username}さん!'

# Cookieを削除するエンドポイント
@app.route('/delete_cookie')
def delete_cookie():
    resp = make_response('Cookieを削除しました!')
    resp.delete_cookie('username')
    return resp

このように、Flaskでは make_response() で生成したレスポンスオブジェクトに対して set_cookie() を呼ぶことで簡単にCookieを操作できます。

🔐 セッションとは何か?

セッションとは、一連のユーザー操作(ページ遷移など)にまたがって状態を保持する仕組みの総称です。「ログインしてからログアウトするまでの一連の流れ」がセッションのイメージです。

セッションにはCookieを内部的に利用するものも多く、「CookieとSessionは別物」というよりは「SessionはCookieを使って実現することが多い上位の概念」と理解するとスッキリします。

セッションの実装方式は大きく2種類あります。

⚖️ クライアントサイドセッション vs サーバーサイドセッション

① クライアントサイドセッション(Flaskのデフォルト)

たとえ話でいうと、「ガラスケースに入れた荷物」です。中身は(Base64デコードすれば)誰でも見えますが、改ざんするとサーバーに検知されます。

Flaskのデフォルトセッションがこの方式で、セッションデータ全体を署名付きCookie(JWTに近い形式)としてブラウザに保存します。secret_key を使った署名により、データの改ざんは検知できますが、中身はBase64デコードで読めてしまいます

  • ✅ サーバーにデータを保存しなくてよい(スケールしやすい)
  • ✅ シンプルで設定が少ない
  • ❌ Cookieのサイズ制限(約4KB)がある
  • ❌ パスワードなどの機密情報は入れてはいけない
  • ❌ セッションを強制失効させにくい
from flask import Flask, session, redirect, url_for, request

app = Flask(__name__)
app.secret_key = 'your-very-secret-key-here'  # 必須!署名に使う

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        # ※本来はパスワード検証も行うこと
        session['username'] = username  # セッションに保存
        return redirect(url_for('dashboard'))
    return '''
        <form method="post">
          <input name="username" placeholder="ユーザー名">
          <button type="submit">ログイン</button>
        </form>
    '''

@app.route('/dashboard')
def dashboard():
    if 'username' not in session:
        return redirect(url_for('login'))
    return f'ようこそ、{session["username"]}さん!'

@app.route('/logout')
def logout():
    session.clear()  # セッションを削除
    return 'ログアウトしました'

② サーバーサイドセッション

たとえ話でいうと、「サーバーが管理している鍵付きロッカー」です。セッションデータはサーバー(RedisやDBなど)に保存され、ブラウザには「ロッカーの鍵(セッションID)」だけがCookieとして渡されます。鍵を持っていてもロッカーの中身は見えません。

  • ✅ 機密情報をブラウザに渡さない
  • ✅ セッションIDを無効化するだけで即座にログアウトできる
  • ✅ 大きなデータも保存できる
  • ❌ RedisやDBなどのサーバー側ストレージが必要
  • ❌ 設定がやや複雑

Flaskでサーバーサイドセッションを実現するには Flask-Session 拡張が便利です。

# pip install Flask-Session redis
from flask import Flask, session
from flask_session import Session

app = Flask(__name__)

# サーバーサイドセッションの設定(Redisを使う例)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SESSION_TYPE'] = 'redis'          # 保存先をRedisに指定
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True       # Cookie側も署名する

import redis
app.config['SESSION_REDIS'] = redis.from_url('redis://localhost:6379')

Session(app)  # Flask-Sessionを初期化

@app.route('/set')
def set_session():
    session['user_id'] = 42  # RedisにID=42を保存、Cookieにはセッションキーのみ
    return 'セッションをサーバー側に保存しました'

@app.route('/get')
def get_session():
    user_id = session.get('user_id', 'なし')
    return f'user_id: {user_id}'

🛡️ セキュリティの注意点

1. secret_key は必ず強力なものを使う

secret_key はCookieの署名・検証に使われます。短すぎたり推測しやすい文字列を使うと、攻撃者に偽のセッションを作られてしまいます。以下のように生成しましょう。

import secrets
print(secrets.token_hex(32))  # 64文字のランダムな16進数文字列を生成
# 例: 'a3f2...b9c1' のような文字列が出力される

2. HttpOnly フラグ

HttpOnly を設定すると、JavaScriptからCookieにアクセスできなくなります。XSS(クロスサイトスクリプティング)攻撃でCookieを盗まれるリスクを下げられます。Flaskでは set_cookie()httponly=True を追加します。

3. Secure フラグ

Secure フラグを設定すると、HTTPS通信のときだけCookieが送信されます。本番環境では必ず設定してください。

resp.set_cookie(
    'session_id',
    value='xxxx',
    httponly=True,   # JavaScriptからアクセス不可
    secure=True,     # HTTPSのみ送信
    samesite='Lax'   # CSRF対策にもなる
)

📊 まとめ比較表

項目 Cookie クライアントサイドセッション サーバーサイドセッション
データ保存場所 ブラウザ ブラウザ(署名付き) サーバー(Redis/DB)
中身の可視性 見える Base64で見える 見えない
改ざん検知 ✅(署名で検知)
強制失効 △(有効期限のみ) ❌(困難) ✅(即座に可能)
サーバー負荷 低い 低い やや高い
主なユースケース 設定保存・トラッキング 小規模アプリのログイン 本番アプリのログイン管理

🤔 どれを使うべき?

  • 📝 学習・プロトタイプ段階クライアントサイドセッション(Flaskデフォルト)で十分。設定が少なく手軽に試せます。
  • 🔒 ログイン情報・決済など機密データが絡むサーバーサイドセッションを選びましょう。データがブラウザに漏れません。
  • 🌐 言語設定・テーマなどユーザー好みの保存Cookieが適しています。長期間保持でき、機密性も不要です。

まとめ

今回はCookie・クライアントサイドセッション・サーバーサイドセッションの違いを解説しました。

  • 🍪 Cookie:ブラウザに保存する小さなデータ。見える・書ける「鍵付きロッカー」
  • 📦 クライアントサイドセッション:署名でデータを守るが中身は見える「ガラスケース」
  • 🔑 サーバーサイドセッション:データをサーバーに隠し、鍵(ID)だけブラウザに渡す

最初はFlaskのデフォルトセッションで動かしてみて、本番環境に移行するタイミングでサーバーサイドセッション+セキュリティフラグの設定を意識するのがおすすめです。ぜひ実際にコードを書いて動かしてみてください!

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る
実践Claude Code入門―現場で活用するためのAIコーディングの思考法

もしも

実践Claude Code入門―現場で活用するためのAIコーディングの思考法

AIコーディングの現場活用法を学ぶ一冊

Amazonで見る
Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

もしも

Python Web開発実践入門 ―― FastAPIによるWebAPI開発と非同期処理

FastAPIでWebAPI開発を実践的に学ぶ

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

📚 関連記事

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。

COMMENT

メールアドレスが公開されることはありません。 が付いている欄は必須項目です