php - 在 MySQL 数据库中使用 SessionHandlerInterface ...请指教

标签 php security

我按照 http://www.php.net/manual/en/class.sessionhandlerinterface.php 制作了以下代码

http://www.wikihow.com/Create-a-Secure-Session-Managment-System-in-PHP-and-MySQL

这里我使用 MySQL 数据库来存储和检索 session 变量。此代码工作正常。但是,如果您能够指出错误并分享您对此代码的意见,那就太好了。

class MySessionHandler implements SessionHandlerInterface
{

    public function open($savePath, $sessionName)
    { 

   $host = 'localhost';
   $user = '******';
   $pass = '******';
   $name = '*******';
   $mysqli = new mysqli($host, $user, $pass, $name);
   $this->db = $mysqli;
   return true;

    }

    public function close()
    {
        return true;
    }

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

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

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

    public function gc($maxlifetime)
    {
        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;
    }

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

}
   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);
   return $decrypted;
   }
}

$handler = new MySessionHandler();
session_set_save_handler($handler, true);
session_start();

谢谢你的时间

干杯

最佳答案

您没有锁定 session 。这是最大的错误。

每当 PHP 中的请求启动 session 并从文件中读取数据时,PHP 会获取该文件的锁,任何并行请求都将停止并等待 session_start() 函数,直到锁已被释放。

如果不加锁,会发生以下情况:第一个请求从数据库中读取所有数据。第二个请求也读取相同的数据。第一个请求将值更改为 A。第二个请求将另一个值更改为 B。第一个请求结束并将其 A 写回数据库。然后第二个请求用它的 B 写回更改,但没有 A。数据丢失!

我注意到的另一件事:为什么要用 base64 对加密数据进行编码?这不是必需的,数据库可以接受二进制数据。这样做的唯一好处是您的托管商可以卖给您更大的机器。

关于php - 在 MySQL 数据库中使用 SessionHandlerInterface ...请指教,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18427204/

相关文章:

php - 无法在 CodeIgniter 中向 PHP 数组添加数据

php - Yii:自定义错误处理转发

php - 我无法将数据插入数据库

java - Spring 安全: Multiple HTTP Config not working

security - 偏执态度: What's your degree about web security concerns?

php - 如何将move_uploaded_file的错误记录到文件中

php - 提取图像路径

.net - 我应该使用什么散列函数来散列小数值?

java - 如何在运行 Selenium 脚本时禁用 chrome 浏览器中的身份验证弹出窗口

php - 了解php中下载文件的位置