セッションとcookieの設計と実装

投稿日:2019年04月15日 08時53分06秒

今までwizdliveという名前で作成してきたアプリケーションサーバですが、cybele(キュベレ)という名前に変更しました。クラウドワークスでコンペして作ってもらったんです。
やはり自分で作らないと才能に満ちあふれていますね。

さてずっと更新してなかったんですが、実はDBMS作ってました。インメモリDBです。selectとかjoinとかCSVからテーブル作るとか一通り作って、今まさに組み込むところです。これはまた後日。

で、アプリケーションサーバなんですが実はセッション実装してませんでした。セッションがあれば色々便利ではありますがパーソナルユースのツールばかり作っていたので、そこまで必要性を感じてませんでした。しかしちょっとしたアプリケーションつくる案件がでてついに実装することになりました。セッションはセッションIDを何度も送る方法とcookieで保存させる方法があり、セキュリティ上はcookieの方が有利です。よって今回はセッションとcookieを同時に設計、実装します。
cookieの概要

基本的にhttp headerでやり取りするようです。
構文は
Set-Cookie : 名前=値; expires=日付; path=パス; domain=ドメイン名; secure
となります。
名前は復数可能で単純に名前の値です。httpヘッダ中ですので特殊文字はダメです。よってURLエンコードして入れるのがいいでしょう。
expiresはcookieの有効期限でGMT形式というので格納します。
domainとpathはどのサイト、ページにcookie参照を許可するかです。省略すると自分の「ホスト名.ドメイン」が指定されます。

ちょっと脇道にそれますが、自分のドメインでないものにcookie送る事ができるんですね。画像見た時に集計用サーバのドメインに情報が集まるようにできるのか。それでウェブ巡回で見た画像から好みとかが集計されちゃうんですね。恐ろしい。

Set-Cookieしたものは期限内なら次回アクセス時にヘッダのcookieの情報に格納されます。
セッションの概要

セッションとはサーバ側に持てるグローバルな値です。本質的にはcookieとは関係ないのですが、cookieを使うとブラウザを終了した後で再度アクセスしても値を保持できます。基本はアクセス固有のキーの値を持たせる事です。PHPを利用している場合はPHPSESSID=kqgrrhk2scqfb338n486q9okp2;のような固有のランダム値が設定されます。これをセッションIDといいます。セッションIDをキーにして内部にデータを保存します。
データを保存するにはメモリ上に持つかDB上に持つかがあります。簡易に実装するならc++のstd::mapを利用してstd::mapとするのがいいでしょう。前半のstringはセッションIDを示し、後半のstringはPHPだと$_SESSIONに相当する変数を用意し、この値をjson_encodeして保存します。
セッション保存の流れ

以上の事からセッションについては以下のような実装で出来そうです。セッションキーはcookieからの取得を優先して追加で_GETでも取れるようにします。これでリンク時、フォームからの送出時にセッションIDを入れる事で、cookieが実装されてないブラウザも対象とすることができます。
値の保存のタイミングは考慮が必要です。何か問題がなければhttp接続が切れてプログラムが終了する時に保存することにします。

1.セッション開始
1.1セッションIDがリクエストヘッダにあれば取得(ついでにGETのパラメータにあっても取得)
1.1.1セッションIDに紐づくデータ復元
1.2なければセッションIDの作成
2.レスポンスヘッダのSet-Cookieにキー変数名=セッションIDを追加
3.プログラム終了時に_SESSIONの値をmap<キー,値>として保存

概ね流れとしてはこんなんで実装していくことにします。

参考「Cookieでセッション管理機能を実現」
サーバー側の実装

追記:
キーをクライアント側とサーバ側で持つのでそれぞれの寿命も問題となります。クライアント側はexpireを指定しなければブラウザの寿命と同じ。そうでない場合は内部のSQLITEに記録されて寿命まで毎回ロードされるでしょう。
サーバ側はphpの場合php.iniまたはsession構造体に記録されているそうです。
ディフォールトはブラウザが閉じるまでの場合1440秒(24分)で、ブラウザを開いていてもセッションは閉じます。
ただしこれはタイマー処理などではなくてセッションにアクセスされる度にチェックされているようだ。よって場合によっては24分以上保持していることもあります。
上とまとめると以下の処理となります
1.セッション開始
1.1セッションIDがリクエストヘッダにあれば取得(ついでにGETのパラメータにあっても取得)
1.1.1セッションIDに紐づくデータ復元
1.2なければセッションIDの作成
2.レスポンスヘッダのSet-Cookieにキー変数名=セッションIDを追加(保持時間はunix timeで指定され、出力時にGMTに変換)
3.タイムアウトのセッションデータを削除
4.プログラム終了時に_SESSIONの値をmap<キー,値>として保存。指定された時間を保持時間として設定

PHPでの設定はこの記事などを参考にしました。
実装すると今までモヤモヤしていたところがクリアになっていいね。

[<< ゼロ知識証明で認証する]

[人工知能は避けて通れない >>]