Reserved characters in PHP $_SESSION variable keys

2019-07-02 00:22发布

问题:

I was looking at the internal representation of PHP session file and I noticed that the session keys are separated by the pipe character |.

Before getting into the problem I encountered, let me give a quick tutorial on how the session file is formatted. At least, this is how it was formatted on my Mac (10.9.4, PHP 5.4.24).

Session File Format

Say I have the following code:

$_SESSION["age"] = 26;
$_SESSION["car"] = "Mazda";
$_SESSION["nerdy"] = true;
$_SESSION["likes"] = array(42, "being meta");
$_SESSION["stats"] = array("bmi" => 1000);

Then it gets stored in the session variable like this:

age|i:26;car|s:5:"Mazda";nerdy|b:1;
likes|a:2:{i:1;i:42;i:2;s:10:"being meta"}
stats|a:1:{s:3:"bmi";i:1000}

The general format is

session_key|session_value[;session_key|value] etc.

where session_value is of the general form

type[:size]:value

More specifically (if anyone's interested),

  • strings: s:3:"some text"
  • integers: i:4
  • booleans: b:1 (true) or b:0 (false)
  • arrays: a:2:{session_value;session_value;session_value;session_value}

where the four session_values in the array of size 2 are the key;value key;value pairs.

The Problem

You can see that in the above, the top-level session keys are separated by the | character. But what if one of our session key names includes the | character?

Well, I tried it. And when I did, the entire session file (in /tmp) was blank (and the variables were definitely not set). Is this an oversight by the PHP devs or an undocumented limitation (or is it documented somewhere)?

This could be easily solved by putting the $_SESSION keys themselves in quotes or backslashing any pipe in a $_SESSION key string. This isn't a big problem for me personally, since I can't fathom why I would need to put a | in a $_SESSION variable key - just curious about it.

回答1:

Its a known bug

https://bugs.php.net/bug.php?id=33786

The work around is update to 5.5.4 and use the php_serialize session serializer



回答2:

Using this php file 'test3.php', I demonstrated that both | (pipe) and ! (bang) will cause _SESSION to fail in PHP 5.4 if they are used in a _SESSION key. Also, no other ASCII characters between 0x20 and 0x7f cause it to fail. I don't have easy access to other versions of PHP to empirically check their behavior.

<?php
session_start( );
?><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Test session keys</title>
</head>
<body>
<form method="post" target="test3.php">
<input type="submit" id="submit" name="submit" value="Submit">
<?php
echo "<br>_SESSION...<br>";
var_dump(  $_SESSION );

echo "\n".'<br><input type="text" id="text" name="text" length="1" ';
if( $_SERVER[ 'REQUEST_METHOD' ] != 'POST' ) {
     $t = chr( 32 );
     echo 'value="&#'.ord( $t ).';">';
     $_SESSION[ 'key' ] = ' ';
     $str = 'first';
} else {
     $str = 'good';
     if( count( $_SESSION ) != 2 ) {
          $str = 'BAD';
     }
     $_SESSION = array( );
     $t = substr( $_POST[ 'text' ], 0, 1);
     echo 'value="&#'.(ord($t) + 1 ).';">';
     $_SESSION[ 'key' ] = chr(ord($t) + 1 );
}
echo "\n".'<br><input type="text" id="check" name="check" length="1" value="&#'.ord( $t ).';">';
echo "\n".'<br><input type="text" id="check2" name="check2" length="6" value="%'.bin2hex( $t ).'";">';
echo '<span id="success"></span>';
echo "<script> document.getElementById( 'success' ).innerHTML = '".$str."'; </script>";

$_SESSION[ "alpha".$_SESSION['key']."four" ]  = 'Hello World';
?>
</form>
</body>
</html>