PHP:セッションを安全なCookieに保存する

Webプロジェクトの開発のある段階で、次のいずれかの状況が発生します。





従来、このような場合、Redis、Memcached、またはその他の外部ストレージがユーザーセッションの保存に使用されていました。 その結果、データベースの運用負担が発生しますが、これはシステムの単一障害点やボトルネックではありません。



ただし、このアプローチに代わるものがあります。 セッションデータが暗号署名で認証されている場合、ユーザー自身のブラウザCookieにセッションデータを安全かつ安全に保存することができます。 これに加えて、データも暗号化されている場合、ユーザーはセッションのコンテンツを利用できません。 この保存方法の主な利点は、セッションに集中型データベースが必要ないことです。これにより、信頼性、速度、およびスケーリングという形で生じるすべての利点が得られます。



メカニズムの説明



このアイデアは新しいものではなく、さまざまなプログラミング言語の多くのフレームワークとライブラリに実装されています。 次に例を示します。





Ruby on Railsでは、セッションを格納する他のすべての方法と比較して、このメカニズムのパフォーマンスに大きな賭けをし、デフォルトで使用することに注意する価値があります。



利用可能な実装のほとんどは次のように機能します。セッションの有効期限、セッションデータ、および有効期限とデータのHMAC署名を含む文字列をCookieに書き込みます。 クライアントの要求に応じて、Cookieは適切なハンドラーによって読み取られ、署名が検証され、現在の時間がセッションの有効期限と比較されます。 すべてが一致した場合、ハンドラーはセッションデータをアプリケーションに返します。



ただし、このメカニズムの一般的な実装では、Cookieは暗号化されません。



従来のアプローチとの比較



その結果、Cookieにセッションを保存することには次の利点があります。





欠点もありますが、それらがない場合:





PHPの実装



PHPに似たものを見つけようとしたときに、最小要件に達するライブラリが1つもないことに驚いた。





さらに、私はそれをまったく不要ではないと考えます:





私がレビューした実装は次のとおりです。

リポジトリ 解説
github.com/Coercive/Cookie 実際、セッションを操作するためのライブラリではありません。 暗号化されたCookieに署名せずに入れます。
github.com/stevencorona/SessionHandlerCookie 要件に最も近いが、依然として重大な欠点があります。

  • サンプルとの直接ハッシュ比較により、 タイムアタックに対して潜在的に脆弱
  • 暗号化なし
  • テストなし
  • 非効率的なCookieパッケージ
  • Cookieの有効期限は値とともに保存されず、署名によってカバーされません。 つまり。 クライアントがセッションでデータを受信すると、それらを際限なく再生できること。
  • 軽微なバグ:1つのスクリプト実行内で書き込み()後の読み取り()が、書き込まれた内容を示さないなど。


github.com/mapkyca/Encrypted-Client-Side-Sessions


また、Slimバージョン2.xフレームワークのCookieにセッションを保存する実装も見ましたが、そこには署名も暗号化もありません。 著者がすぐに警告するもの。



署名の代わりに署名の検証と暗号化が重要なのはなぜですか? まず、特にセッションレコードが短いセッションでは、ガベージを含むCookieが復号化される可能性が顕著にあります。 第二に、セッションのある回線はデシリアライズされ、信頼できないソースからの回線はデシリアライザーの入力に送信できません。



すべての検索の後、私はそのようなライブラリを自分で実装することにしました。



独自の実装



Packagist: packagist.org/packages/snawoot/php-storageless-sessions

Github: github.com/Snawoot/php-storageless-sessions

composerからのインストール: composer require snawoot/php-storageless-sessions







主な機能:





暗号化モードの選択に関するいくつかの言葉。 ブロック暗号化モード(ECB、CBC)を使用すると、暗号文の長さがわずかに長くなります。 これは、元のメッセージの長さがブロックのサイズの倍数でなければならないためです。 必須のパディングのため、長さの増加は1バイトから暗号ブロックのサイズまでです。 つまり、AESの場合は1〜16バイトです。 ストリーム暗号化モード(OFB、CFB、CTRなど)を使用する場合、元のメッセージはブロック暗号を通過せず、代わりにブロック暗号を使用してガンマシーケンスを形成し、暗号テキストの長さが元のメッセージの長さと正確に一致します。タスク。



使用例



このハンドラーを使用する方法を示す小さなスクリプト:



 <?php require_once("vendor/autoload.php"); header('Content-Type: text/plain'); $secret = '********************'; $handler = new VladislavYarmak\StoragelessSession\CryptoCookieSessionHandler($secret); session_set_save_handler($handler, true); session_start(); if ($_GET) { foreach ($_GET as $key => $value) $_SESSION[$key] = $value; echo "Updated session:"; } else echo "Current session data:\n"; var_dump($_SESSION);
      
      





https://vm-0.com/sess.phpのクエリ行で異なるセッション値を設定することにより、その動作を観察できます



symfony統合の例:



 framework: session: handler_id: session.handler.cookie services: session.handler.cookie: class: VladislavYarmak\StoragelessSession\CryptoCookieSessionHandler public: true arguments: ['reallylongsecretplease']
      
      







実際のデモとして、私はこのセッションハンドラーを、セッションを使用することを思いついた最初のWebアプリケーションに接続しました。 DokuWiki: wiki.vm-0.comであることが判明しました。 サイトには登録とログインがあり、セッションの作業はCookieで確認できます。



ご清聴ありがとうございました。この記事がプロジェクトの発展に役立つことを願っています。



All Articles