Flask のデフォルトセッションはクライアント側の Cookie に保存される。署名により改ざんは検知できるが、内容は暗号化されていないため、機密情報を入れてはいけない。
Flask セッションの仕組み
Flask のセッションは itsdangerous ライブラリで署名されている。
from flask import Flask, session
app = Flask(__name__)
app.secret_key = 'your-secret-key'
@app.route('/login')
def login():
session['user_id'] = 123
session['role'] = 'admin' # これは読める
return 'Logged in'
ブラウザの開発者ツールで Cookie を確認すると、session という名前の値が見える。
セッション Cookie の中身を見る
セッション Cookie は Base64 エンコードされた JSON であり、簡単にデコードできる。
import base64
cookie = 'eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiJ9...'
# ドットより前がペイロード
payload = cookie.split('.')[0]
# Base64 デコード
decoded = base64.urlsafe_b64decode(payload + '==')
print(decoded) # b'{"user_id":123,"role":"admin"}'
このように、セッションに保存した内容は誰でも読める。
入れてはいけないもの
パスワードやパスワードハッシュ
クレジットカード情報
個人を特定できる機密情報(マイナンバーなど)
API キーやトークン
署名の役割
署名は改ざんを検知するためのものであり、秘匿のためではない。
# 攻撃者が role を admin に書き換えようとしても
# 署名が一致しないので Flask が拒否する
ただし、secret_key が漏洩すると攻撃者は有効な署名を生成できてしまう。secret_key は十分に複雑な値を設定し、絶対に外部に漏らさないこと。
安全な代替手段
機密情報はサーバーサイドに保存し、セッションには ID だけを入れる。
@app.route('/login')
def login():
session['session_id'] = generate_session_id()
# 機密情報は Redis やデータベースに保存
redis.hset(f'session:{session_id}', 'credit_card', '****')
return 'Logged in'
Flask-Session を使えば、セッション自体をサーバーサイドに保存できる。
from flask_session import Session
app.config['SESSION_TYPE'] = 'redis'
Session(app)
この設定では Cookie にはセッション ID のみが保存され、実際のデータは Redis に格納される。