
とある会社のシステムを構築している時に、PHPセッション+JWT(ジョット)を使ったAPIトークンのセキュリティをやることになり、
基本的に認証Hashコードのみで対応しているつくりだったものを、Session対応する際の備忘録をブログに残しておきたいと思います。
PHPフレームワークなどを使っている場合は何の問題もないんですが、フロントエンド+バックエンドでサーバー負荷軽減などを行う便利フレームワークが今の所見つけられていないので、
とりあえず自作しているという方の参考になればと思います。
Sessoin保持時間の記述
普通に次の様に書くだけじゃ、Sessionが自動で削除されませんでした。
ini_set('session.gc_maxlifetime', 5);// セッション保持を5秒にセット
session_start(); // セッション開始
わかりやすく確認するために、5秒でセッションが切れる様にしています。
上記だと、PHPがセッションを終了しても、データを切り離してくれないので、セッションが残った状態になるようです。
そこで、次のコードを追記。
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1);
PHPは、session.gc_probability と session.gc_divisor の、値によって、確率的にガベージコレクションが実行されるので、
これを共に1にすることで、毎回ガベコレが実行されるようになります。
でも、実はこれだけでも、Sessionが5秒後に消えることはなく、ブラウザ表示しても残った状態のままでした。
原因は 、Cookieの保持時間です。
session_set_cookie_params(5);// クッキーの有効期限も5秒に設定
さらにコレを追記することで、cookieも寿命が5秒にすることができます。
これで無事に、5秒で消えるSessionが実現できました。
最後に、今回の全部入りのコードは次の様になっています。
<?php
ini_set('session.gc_maxlifetime', 5);
ini_set('session.gc_probability', 1);
ini_set('session.gc_divisor', 1);
session_set_cookie_params(5);
session_start();
これを、PHP実行の最初に記述しておけば、Sessionタイムをコントロールすることができます。
でも、実際は、Cookieは、ブラウザ側で残り続ける可能性も高いので、その場合は、次のコードを書いて、強制的にsession_idをgenerateすることができます。
session_regenerate_id(true);
javascript->PHPへのAPI問い合わせ方法
これまでは、特定のファイル(jsonなどのsetting系のデータ系)で、任意のhash文字列をおいて、
javascript問い合わせの時に、との値を、リクエストヘッダに任意のkeyでくっつけてそれをサーバー側で同じ値であれば、apiリクエストを受け付ける様にしていました。
もし、値が違っていると403エラーを返すし、そもそもヘッダリクエストがない場合も否認するようにできますが、
この任意の値ファイルが流出すると、誰でも比較的簡単にAPI問い合わせができてしまいます。
API問い合わせを、このサイトに来た人のみに限定する場合に、もう少しイケてる方法で判定できる方法を思いつきました。
API問い合わせの鉄板方式
まず、JavascriptからAPI問い合わせをする場合、セッション毎に、任意の識別子を発行して、それをkeyとして、ヘッダリクエストに貼り付ける様にすればいいだけです。
その任意の識別子は、サーバー側で発行すればいいので、uniqid() で発行するだけで効果絶大です。
そもそも、サーバー側では、その識別子を、sessionデータとして保持しておくことで、発行したブラウザとの連携が可能になります。
発行手順は次の通りです。
1. ページ表示時に、uniqid()で任意の値を発行
2. $_SESSION["auth_key"]に、任意値を保持
3. javascriptに、任意値を受け渡し。cookieでもいいし、scriptタグに、window.auth_key = "任意値" としてもいいです。
そして、APIアクセステジュンんは次の通り
1. javascriptのfetchなどに、リクエストヘッダに任意値を入れる。
2. サーバ側で、受け取ったヘッダリクエストの任意値と、$_SESSION["auth_key"]を比較する。
このシンプルな仕様で、セッション毎に使い捨てできる、鍵データを発行して、仮に他のブラウザでその任意値でアクセスしたとしても、API起動できないので、かなり安心です。
あとがき
今回は、API問い合わせ手順に関する、あまり他のサイトで見たことが無い、独自の手順を紹介しましたが、
発行した任意の値に、session_idを埋め込んだり、複合して暗号化することで、より複雑なトークンkeyが扱える様になるので、セキュリティの深さを改めて認識することができました。
ちなみに、個人情報などをサーバーとやりとりする手順なども、今後バニラ開発してみたいと思います。
0 件のコメント:
コメントを投稿