Blow Up by Black Swan

Python-Flaskのsessionを分解してみた

最近、Flaskについて複数の記事を書きました。今回はその流れでFlaskのsessionを分解してみた記事です。以前、かなりわかりやすい記事があったのですが、ブログが閉鎖されてしまったようで見れなくなっていたので、自分で調べ直してまとめたものです。深い部分まで分解しきれていませんが、Flaskのsessionの構造について理解は深まるのでは無いかと思います。この記事が一人でも多くの方の参考になりましたら、幸いです。

1. Flaskのsessionの構造

Flaskのsession機能は、サーバ側でIDなどのデータにタイムスタンプと署名を表すランダムな文字列を結合させた文字列をレスポンスのヘッダーに持たせる機能です。一般的なsessionと基礎的な部分では代わりないと思います。このランダムな文字列を生成するのにFlaskではitsdangerousモジュールを利用しています。Flaskのsessionの構造を図示すると概ね次のようになっています。

session-architect

前回記事で作成したブログ記事では、ユーザIDをセッションに持たせていましたが、これはhedersの”Cookie”欄にセットされます。セッションデータはドットで結合されており、左からそれぞれセッションデータ、タイムスタンプ、署名を表しています。次の章では、sessionからセッションデータとタイムスタンプの値を取り出します。

2. Flaskのsessionを分解してみる

ここでは以前記事にしたFlaskチュートリアルに記載されているブログアプリケーション、flaskrで取得したsessionデータを使います。ローカルでアプリケーションを立ち上げ、ログインした状態でheaderに記載されているsession情報を描きスクリーンショットのように取得します。グーグルクロムの検証の使い方は省略していますので、ご存じ無い方はググってみて下さい。

flask_session

なお、シークレットキーは「dev」になっていますが、sessionデータとタイムスタンプを取り出す分には特に必要ありません。署名の部分で活用されていると思われます。

from itsdangerous import base64_decode
from datetime import datetime

cookie_session = "eyJ1c2VyX2lkIjoxfQ.XavBaQ.DcFq7AqdKl0LI32BKua-_f8Nt3c"
data, timestamp, secret = cookie_session.split('.')
d = base64_decode(data)
t = datetime.fromtimestamp(int.from_bytes(base64_decode(timestamp),byteorder='big'))
print(d)
print(t)

cookie_session変数の値は、ドット区切りでそれぞれ左からセッションデータ、タイムスタンプ、署名となっています。セッションデータを復元するにはitsdangerousモジュールbase64_decodeメソッドを使います。タイムスタンプは、デコードした後にバイトデータをint型に変換し、変換されたUNIXスタンプをdatetime型に組み直すという3重の変換作業をしています。戻り値は以下になります。

# 戻り値

b'{"user_id":1}'
2019-10-20 11:07:37

3. 最後に

以上がflaskのsessionの分解方法になります。初めてこれを知った時は、分解できるという事実にとても驚きましたが、シークレットキーを使って改ざんを防ぐ仕組みも併せて把握することができ、Flaskへの理解を深めることができたと感じました。元ネタのブログ記事はもう少し詳細に記述していたと記憶しているのですが、そのブログが復活することがあればその時は主要参考サイトとして紹介したいと思います。なお、この記事を作成するにあたってその記事がなくなってしまったため、海外のブログ記事をいくつか参考にしました。下記にリンクを張っていますので、参考にして頂ければと思います。読んで頂き、ありがとうございました。