Hướng dẫn php session encryption - mã hóa phiên php

Xin chào các bạn, ngày hôm nay mình xin chia sẻ cách tạo ra session bảo mật bằng cách sử dụng PHP kết hợp cùng MySQL encrypted cực mạnh bằng cách thức: 256-bit AES encryption.

Đây là một class cần thiết cho tất cả những ai đang phải đối mặt với dự án nhiều “subdomain” như mạng xã hội chẳng hạn, mỗi một sub sẽ tạo ra một session khác nhau nên sẽ làm cho bạn lúng túng mỗi khi muốn kiểm tra “chìa khóa” của người dùng xem có khớp không và có cùng session không, có nhiều cách khác nhau để giải bài toán này nhưng tôi xin chia sẻ cách mà tôi nghĩ là “tốt nhất” cho các bạn.

Bước 1: Tạo bảng:

CREATE DATABASE `secure_sessions` ;

Tôi lấy ví dụ là mình sẽ tạo ra bảng

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
4

Bước 2: Tạo một người dùng mới có quyền

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
5

  • User: “sec_user” “sec_user”
  • Password: “eKcGZr59zAa2BEWU” “eKcGZr59zAa2BEWU”

( đừng dùng mật khẩu ví dụ )

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';

* Xin lưu ý với các bạn là nếu host của các bạn không cho phép thêm người dùng thì … bó tay nhé !

Bước 3: Tạo một bảng có tên là sessions với các trường

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
6.

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;

CHARSET bạn có thể đặt latin1 cho tiết kiệm bộ nhớ, hơn là

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
7, sử dụng kiểu dữ liệu
CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
8 nhằm tiết kiệm bộ nhớ cho cơ sở dữ liệu đấy 😛

Bước 4: Tạo file session.class.php

Bạn hãy tạo một class tên là

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
9, cách tạo class thì các bạn search trên mạng nhé, à quên, nếu không biết tạo class thì bạn nên dừng lại ở đây và chuyển sang đọc bài khác cho tiết kiệm thời gian.

function __construct() {
   // set our custom session functions.
   session_set_save_handler(array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'), array($this, 'destroy'), array($this, 'gc'));

   // This line prevents unexpected effects when using objects as save handlers.
   register_shutdown_function('session_write_close');
}

Khởi động class bằng

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;
0 như trên.

Tiếp theo, tạo function

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;
1 trong class này:

function start_session($session_name, $secure) {
   // Make sure the session cookie is not accessable via javascript.
   $httponly = true;

   // Hash algorithm to use for the sessionid. (use hash_algos() to get a list of available hashes.)
   $session_hash = 'sha512';

   // Check if hash is available
   if (in_array($session_hash, hash_algos())) {
      // Set the has function.
      ini_set('session.hash_function', $session_hash);
   }
   // How many bits per character of the hash.
   // The possible values are '4' (0-9, a-f), '5' (0-9, a-v), and '6' (0-9, a-z, A-Z, "-", ",").
   ini_set('session.hash_bits_per_character', 5);

   // Force the session to only use cookies, not URL variables.
   ini_set('session.use_only_cookies', 1);

   // Get session cookie parameters 
   $cookieParams = session_get_cookie_params(); 
   // Set the parameters
   session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], $secure, $httponly); 
   // Change the session name 
   session_name($session_name);
   // Now we cat start the session
   session_start();
   // This line regenerates the session and delete the old one. 
   // It also generates a new encryption key in the database. 
   session_regenerate_id(true); 
}

Tiếp theo: tạo function Open:

function open() {
   $host = 'localhost';
   $user = 'sec_user';
   $pass = 'eKcGZr59zAa2BEWU';
   $name = 'secure_sessions';
   $mysqli = new mysqli($host, $user, $pass, $name);
   $this->db = $mysqli;
   return true;
}

Sau đó phải có đóng lại chứ:

function close() {
   $this->db->close();
   return true;
}

Tiếp theo, ta tạo function read, hàm này sẽ được thực thi bởi php khi ta gọi

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;
2;

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;
}

a* Lưu ý: hàm này thực thi nhiều lần, sẽ là nhiều lần đấy, nên ngoài nghĩ tới tối ưu ra ta còn phải nghĩ tới tốc độ tải của server, và trong hàm trên ta đang giải nén key từ cơ sở dữ liệu sử dụng mã hóa 256-bit AES encryption.

Tiếp theo ta tại function write:

function write($id, $data) {
   // Get unique key
   $key = $this->getkey($id);
   // Encrypt the data
   $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;
}

* Lưu ý: Hàm này được gọi khi chúng ta gán một giá trị vào Session, ví dụ như :

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;
3 Hàm này sẽ mã hóa toàn bộ giá trị và ghi vào cơ sở dữ liệu.

Tiếp theo là hàm __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;
}

* Hàm này sẽ xóa toàn bộ dữ liệu mã hóa của session khi chúng ta gọi session__destroy(); trong PHP.

Bước tiếp theo ta tạo hàm gc (garbage collector);gc (garbage collector);

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
0

* Lưu ý: Hàm này là “garbage collecter” và được gọi để xóa các session cũ trong cơ sở dữ liệu, tần xuất được gọi tới của hàm này được quyết định bởi cấu hình của

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;
4 và
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;
5 nhé !

Tiếp theo, ta tạo hàm getkey():

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
1

* Hàm này dùng để lấy một key duy nhất để mã hóa theo phương thức mã hóa trên, được lấy từ bảng session. Nếu không có thì nó tự tạo ra một key hoàn toàn mới theo dạng “random” …

Bước tiếp theo là ta sẽ tạo ra hai hàm để mã hóa và giải mã theo cách thức mã hóa mà chúng ta chọn:

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
2

* Hai hàm này mã hóa dữ liệu của bảng session, sử dụng key mã hóa từ cơ sở dữ liệu và mỗi session đều có giá trị riêng của nó. Vậy là chúng ta không những sử dụng key đã được mã hóa mà còn làm cho key này bảo mật hơn-cả-random 🙂

Bước 5: Hoàn thành class, gọi trong bất kỳ một file PHP nào:

CREATE USER 'sec_user'@'localhost' IDENTIFIED BY 'eKcGZr59zAa2BEWU';
GRANT SELECT, INSERT, UPDATE, DELETE ON `secure_sessions`.* TO 'sec_user'@'localhost';
3

* Trên là cách gọi session hoặc gán session vào một giá trị.

Chúc mừng các bạn, bây giờ các bạn đã có một bảng session ngang ngửa với của PHP tạo ra, ngoài ra chúng ta còn có thể đếm được số người đang trực tuyến, hoặc class session này sẽ cực kỳ hữu dụng cho những ai tạo ra các dự án có nhiều subdomain kiểu như mạng xã hội chẳng hạn, vì đặc điểm của PHP là tạo ra session mới cho mỗi subdomain nên cần phải sử dụng class này để giải quyết triệt để vấn đề.

Chúc các bạn thành công !