安全なセッション管理システムの作り方 i

ページ名:安全なセッション管理システムの作り方 i

このガイドでは、セッションをmySQLデータベースに安全に格納する方法を説明します。また、データベースに入るすべてのセッションデータを暗号化します。つまり、もし誰かがデータベースに侵入することに成功した場合、すべてのセッションデータは256ビットAES暗号化によって暗号化されます。

方法1

mySQLデータベースを設定する

  1. MySQLデータベースを作成します。
    このガイドでは、"secure_sessions" という名前のデータベースを作成します。
    作成方法はこちらを参照してください。
    または、以下のSQLコードを使用して作成することもできます。

    データベースの作成コード
    CREATE DATABASE `secure_sessions` ;
    注:一部のホスティングサービスでは、phpMyAdminからデータベースを作成することができません。
  2. SELECT、INSERT、DELETE権限のみを持つユーザーを作成します。
    これは、スクリプトにセキュリティ違反があっても、ハッカーがデータベースからテーブルを削除できないことを意味します。 本当に偏執狂的な場合は、関数ごとに異なるユーザーを作成してください。

    • ユーザー:"sec_user"
    • パスワード: "eKcGZr59zAa2BEWU"


    ユーザー・コードを作成する:
    CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU'; GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';

    注意: 自分のサーバーで実行する場合は、上記のコードのパスワードを変更することをお勧めします。(PHPのコードも必ず変更してください。) 覚えやすいパスワードである必要はないので、できるだけ複雑なパスワードにしてください。ここにジェネレーターがあります。
  3. セッション」という名前のMySQLテーブルを作成します。
    以下のコードは、4つのフィールド(id、set_time、data、session_key)を持つテーブルを作成します。

    sessions "テーブルを作成する:
    CREATE TABLE `sessions` ( `id` char(128) NOT NULL, `set_time` char(10) NOT NULL, `data` text NOT NULL, `session_key` char(128) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
    フィールド "id "と "session_key "は常に128文字なので、長さがわかっているフィールドにはCHARデータ型を使用します。ここでCHARを使うことで、処理能力を節約できる。
方法2

session.class.phpファイルを作成する

  1. クラスを作成します。
    新しいクラスを開始するには、以下のコードを入力する必要があります:

    新しいクラスを作成します:
    クラス session {
  2. construct関数を作成します。
    この関数は、'session' クラスを使用してオブジェクトの新しいインスタンスを作成するたびにコールされます。PHP の __construct 関数についてはこちらを参照ください。
    この関数は、カスタムセッションハンドラを設定し、 クラスがインスタンス化 (つまり、作成/構築/構築) されるとすぐに使用できるようにします。

    __construct関数です:
    function __construct() { // 独自のセッション関数を設定します。 session_set_save_handler(array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'), array($this, 'destroy'), array($this, 'gc')); // この行は、保存ハンドラとしてオブジェクトを使用する際に予期しない影響が発生するのを防ぎます。 register_shutdown_function('session_write_close'); }.
  3. start_session関数を作成します。
    この関数は新しいセッションを開始するたびに呼び出されるので、session_start();の代わりに使ってください。各行が何をするのかは、コード中のコメントを参照してください。

    start_session 関数です:
    function start_session($session_name, $secure) { // セッションクッキーが javascript からアクセスできないことを確認する $httponly = true; // セッションに使用するハッシュアルゴリズム。(使用可能なハッシュのリストを取得するには hash_algos() を使用します。) $session_hash = 'sha512'; // ハッシュが使用可能かどうかをチェックします if (in_array($session_hash, hash_algos())){ini_set('session.hash_function', $session_hash); } // ハッシュの一文字あたりのビット数。 // ini_set('session.hash_bits_per_character', 5); // URL変数ではなく、クッキーのみを使用するようにセッションを強制する。use_only_cookies', 1); // セッションクッキーのパラメータを取得する $cookieParams = session_get_cookie_params(); // パラメータを設定する session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $secure, $httponly); // セッション名を変更します session_name($session_name); // これで、セッションを開始することができます session_start(); // この行でセッションを再生成し、古いセッションを削除します。 // また、データベースに新しい暗号鍵を生成します。 session_regenerate_id(true); }.
  4. オープン関数を作成します。
    この関数は、新しいセッションを開始する際に PHP セッションからコールされます。

    新しいデータベース接続を開始するために使用します:
    function open() { $host = 'localhost'; $user = 'sec_user'; $pass = 'eKcGZr59zAa2BEWU'; $name = 'secure_sessions'; $mysqli = new mysqli($host, $user, $pass, $name); $this->db = $mysqli; return true; }.
  5. close 関数を作成します。
    この関数は、セッションを閉じたいときにコールされます。

    close 関数を作成します:
    function close() { $this->db->close(); return true; }.
  6. read 関数を作成します。
    この関数は、たとえば echo $_SESSION['something']; を使用してセッションにアクセスしようとしたときに PHP からコールされます。ひとつのページでこの関数が何度もコールされる可能性があるため、 セキュリティのためだけでなくパフォーマンスのためにもプリペアドステートメントを使用します。文を準備するのは一度だけで、あとは何度でも実行できます。
    また、データベースで暗号化されたセッションデータを復号化します。セッションには256ビットのAES暗号を使用しています。

    read 関数を使用します:
    function read($id) { if(!isset($this->read_stmt)) { $this->read_stmt = $this->db->prepare("SELECT data FROM sessions WHERE id = ?LIMIT 1"); } $this->read_stmt->bind_param('s', $id); $this->read_stmt->execute(); $this->read_stmt->store_result(); $this->read_stmt->bind_result($data); $this->read_stmt->fetch(); $key = $this->getkey($id); $data = $this->decrypt($data, $key); return $data; }.
  7. write 関数を作成します。
    この関数は、セッションに値を代入する際に使用します。 たとえば $_SESSION['something'] = 'something else'; のようにします。この関数は、データベースに挿入されるすべてのデータを暗号化します。

    書き込み関数です:
    function write($id, $data) { // 一意なキーを取得します $key = $this->getkey($id); // データを暗号化します $data = $this->encrypt($data, $key); $time = time(); if(!isset($this->w_stmt)) { $this->w_stmt = $this->db->prepare("REPLACE INTO sessions (id, set_time, data, session_key) VALUES (? , ?, ?, ?)"); // データを暗号化します。, ?, ?, ?)"); } $this->w_stmt->bind_param('siss', $id, $time, $data, $key); $this->w_stmt->execute(); return true; }.
  8. destroy 関数を作成します。
    この関数は、セッションをデータベースから削除します。 php が session__destroy(); のような関数をコールする際に使用します。

    destroy関数を使用します:
    function destroy($id) { if(!isset($this->delete_stmt)) { $this->delete_stmt = $this->db->prepare("DELETE FROM sessions WHERE id = ?"); } $this->delete_stmt->bind_param('s', $id); $this->delete_stmt->execute(); return true; }.
  9. gc (ガベージコレクタ) 関数を作成します。
    この関数はガベージコレクタ関数で、古いセッションを削除する際にコールされます。この関数が呼び出される頻度は、session.gc_probabilityとsession.gc_divisorという2つの設定ディレクティブによって決まります。

    関数
    function gc($max) { if(!isset($this->gc_stmt)) { $this->gc_stmt = $this->db->prepare("DELETE FROM sessions WHERE set_time < ?"); } $old = time() - $max; $this->gc_stmt->bind_param('s', $old); $this->gc_stmt->execute(); return true; }.
  10. getKey 関数を作成します。
    この関数は、セッションテーブルから暗号化用の一意なキーを取得するために使用します。セッションがない場合は、暗号化用の新しいランダムキーを返します。

    getkey() 関数を使用します:
    private function getkey($id) { if(!isset($this->key_stmt)) { $this->key_stmt = $this->db->prepare("SELECT session_key FROM sessions WHERE id = ?LIMIT 1"); } $this->key_stmt->bind_param('s', $id); $this->key_stmt->execute(); $this->key_stmt->store_result(); if($this->key_stmt->num_rows == 1) { $this->key_stmt->bind_result($key); $this->key_stmt->fetch(); return $key; } else { $random_key = hash('sha512', uniqid(mt_rand(1, mt_getrandmax()), true)); return $random_key; } }.
  11. 暗号化関数と復号化関数を作成します。
    これらの関数はセッションのデータを暗号化し、セッションごとに異なるデータベースからの暗号化キーを使用します。このキーを直接暗号化に使用するわけではありませんが、キーのハッシュをよりランダムにするために使用します。

    関数 encrypt() および decrypt() を使用します:
    private function encrypt($data, $key) { $salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH'; $key = substr(hash('sha256', $salt.$key.salt), 0, 32); $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); encrypted = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_ECB, $iv)); return $encrypted; } private function decrypt($data, $key) { $salt = 'cH!swe!retReGu7W6bEDRup7usuDUh9THeD2CHeGE*ewr4n39=E@rAsp7c-Ph@pH'; $key = substr(hash('sha256', $salt.$key.salt), 0, 32); $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB); $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($data), MCRYPT_MODE_ECB, $iv); $decrypted = rtrim($decrypted, "\0"); return $decrypted; }.
  12. クラスを終了します。
    ここでは、クラスを中かっこで囲んで終わらせています:

    クラスを終了します:
    }
方法3

セッションを使ってページを作成する

  1. カスタム・セッション・マネージャーでセッションを使用します。
    セッションにアクセスしたいすべてのページで、session_start()の代わりにこれを使う必要があります;

    セッションの開始
    セッションを開始する: require('session.class.php'); $session = new session(); // https を使用する場合は true を設定する $session->start_session('_s', false); $_SESSION['something'] = '値'; echo $_SESSION['something'];
この記事は、CC BY-NC-SAの下で公開された " How to Create a Secure Session Management System in PHP and MySQL "を改変して作成しました。特に断りのない限り、CC BY-NC-SAの下で利用可能です。

シェアボタン: このページをSNSに投稿するのに便利です。

コメント

返信元返信をやめる

※ 悪質なユーザーの書き込みは制限します。

最新を表示する

NG表示方式

NGID一覧