Doc #70520 [Ana]: session_regenerate_id() "Failed to create session ID" with custom SessionHandler
| From: | yohgaki@php.net | Date: | Fri, 18 Sep 2015 22:41:26 +0000 |
| Subject: | Doc #70520 [Ana]: session_regenerate_id() "Failed to create session ID" with custom SessionHandler | ||
| References: | 1 | Groups: | php.doc.bugs |
| Request: | Send a blank email to doc-bugs+get-12766@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=70520&edit=1
ID: 70520
Updated by: yohgaki@php.net
Reported by: hpdl at oscommerce dot com
Summary: session_regenerate_id() "Failed to create session
ID" with custom SessionHandler
Status: Analyzed
Type: Documentation Problem
Package: Session related
Operating System: Win10
PHP Version: 7.0.0RC3
Assigned To: yohgaki
Block user comment: N
Private report: N
New Comment:
Since mcrypt seems to have problems https://bugs.php.net/bug.php?id=70529 , I've
made new example using OpenSSL AES. Any comments on this new sample code?
There are too many ini_set() etc, I'll get rid of irrelevant code for the doc later.
<?php
ob_start();
error_reporting(E_ALL | E_STRICT);
ini_set('session.save_path', '/tmp');
ini_set('display_errors', true);
/**
* decrypt AES 256
*
* @param data $edata
* @param string $password
* @return dencrypted data
*/
function decrypt($edata, $password) {
$data = base64_decode($edata);
$salt = substr($data, 0, 16);
$ct = substr($data, 16);
$rounds = 3; // depends on key length
$data00 = $password.$salt;
$hash = array();
$hash[0] = hash('sha256', $data00, true);
$result = $hash[0];
for ($i = 1; $i < $rounds; $i++) {
$hash[$i] = hash('sha256', $hash[$i - 1].$data00, true);
$result .= $hash[$i];
}
$key = substr($result, 0, 32);
$iv = substr($result, 32,16);
return openssl_decrypt($ct, 'AES-256-CBC', $key, true, $iv);
}
/**
* crypt AES 256
*
* @param data $data
* @param string $password
* @return base64 encrypted data
*/
function encrypt($data, $password) {
// Set a random salt
$salt = openssl_random_pseudo_bytes(16);
$salted = '';
$dx = '';
// Salt the key(32) and iv(16) = 48
while (strlen($salted) < 48) {
$dx = hash('sha256', $dx.$password.$salt, true);
$salted .= $dx;
}
$key = substr($salted, 0, 32);
$iv = substr($salted, 32,16);
$encrypted_data = openssl_encrypt($data, 'AES-256-CBC', $key, true, $iv);
return base64_encode($salt . $encrypted_data);
}
class EncryptedSessionHandler extends SessionHandler
{
private $key;
public function __construct($key)
{
$this->key = $key;
}
public function read($id)
{
$data = parent::read($id);
if ($data === "") {
return "";
} else {
return decrypt($data, $this->key);
}
}
public function write($id, $data)
{
$data = encrypt($data, $this->key);
return parent::write($id, $data);
}
}
ini_set('session.save_handler', 'files');
$key = substr(sha1(random_bytes(24)), 0, 24);
$handler = new EncryptedSessionHandler($key);
session_set_save_handler($handler, true);
echo '<pre>';
session_start();
$_SESSION['key'] = 1234;
var_dump($_SESSION);
echo session_id() . PHP_EOL;
session_regenerate_id(true);
echo session_id() . PHP_EOL;
Previous Comments:
------------------------------------------------------------------------
[2015-09-18 09:47:24] hpdl at oscommerce dot com
Thanks for the pointers here. The error occurred with my database session handler read() method
returning a bool false instead of a string. This was only caught in RC3 as earlier 7dev releases and
previous PHP versions did not produce any kind of error.
Thanks for the time spent on this.
------------------------------------------------------------------------
[2015-09-18 09:21:46] yohgaki@php.net
I see error for read, but it will fail on both read/write due to wrong key size.
------------------------------------------------------------------------
[2015-09-18 09:19:20] yohgaki@php.net
s/write/read/
------------------------------------------------------------------------
[2015-09-18 09:18:26] yohgaki@php.net
Found what's wrong.
Current session save handler expects session read function returns STRING type when there is no
error.
However, the code
public function read($id)
{
$data = parent::read($id);
return @mcrypt_decrypt(MCRYPT_3DES, $this->key, $data, MCRYPT_MODE_ECB);
}
returns non string because $this->key is not valid key length.
Apparently, the document has wrong size of key which results mcrypt_decrypt() error. This makes fail
to write session data.
Making documentation problem.
------------------------------------------------------------------------
[2015-09-18 09:05:41] requinix@php.net
I tried it with a session_save_path(".") immediately before the session_start(). CWD was a
local directory, and when I ran the code I posted earlier (in the same location) it worked
correctly.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=70520
--
Edit this bug report at https://bugs.php.net/bug.php?id=70520&edit=1