Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safety of these methods to encode and decode PHP sessions

In a way this question can be seen as an extension of this one.

We're considering releasing a class that handles deserializing and serializing session data stored in a table on a large scale production website so that we can edit arbitrary session data.

Problem is, session_decode() populates the current $_SESSION without returning a decoded array, and session_encode() doesn't encode a given array (it only returns a serialized string of the current session.)

The default PHP session serialize handler doesn't simply use serialize() to encode the sessions, and therefore the only way to get the same functionality of encoding and decoding a session is by either moving the global $_SESSION variable around (i.e store into session, retrieve data and restore) or by trying to reproduce an implementation of what the session.serialize_handler does.

We opted for the latter reproduction approach as it seems less instrusive. There have been a number of attempts at this reproduction in the comments section of session_encode and session_decode in the docs. I've picked out two that I think seemed the most reliable and applied them. The decode method seems quite robust but the encode method although it works, was posted over 5 years ago

We're still reluctant to roll it out simply because there may be unseen edge cases that will cause these methods to break.

Ultimately, I'm looking for:

  • examples that will break the methods below, or
  • reassurance that these methods have been used in production and won't break
  • perhaps alternatives that have been tried and tested in production?

Thanks everyone in advanced!

The code:

class Session extends BaseSession
{
    /**
     * Taken from http://www.php.net/manual/en/function.session-decode.php#108037
     */
    public function unserialized() {
        $session_data = $this->content;
        $method = ini_get("session.serialize_handler");
        switch ($method) {
            case "php":
                return self::unserialize_php($session_data);
                break;
            case "php_binary":
                return self::unserialize_phpbinary($session_data);
                break;
            default:
                throw new Exception("Unsupported session.serialize_handler: " . $method . ". Supported: php, php_binary");
        }
    }

    /**
     * Taken from http://www.php.net/manual/en/function.session-encode.php#76425
     */
    public function serialize($array, $safe = true) {
        // the session is passed as refernece, even if you dont want it to
        if( $safe ) $array = unserialize(serialize( $array )) ;
        $raw = '' ;
        $line = 0 ;
        $keys = array_keys( $array ) ;
        foreach( $keys as $key ) {
            $value = $array[ $key ] ;
            $line ++ ;
            $raw .= $key .'|' ;
            if( is_array( $value ) && isset( $value['huge_recursion_blocker_we_hope'] )) {
                $raw .= 'R:'. $value['huge_recursion_blocker_we_hope'] . ';' ;
            } else {
                $raw .= serialize( $value ) ;
            }
            $array[$key] = Array( 'huge_recursion_blocker_we_hope' => $line ) ;
        }

        $this->content = $raw;
        $this->save();
    }


    private static function unserialize_php($session_data) {
        $return_data = array();
        $offset = 0;
        while ($offset < strlen($session_data)) {
            if (!strstr(substr($session_data, $offset), "|")) {
                throw new Exception("invalid data, remaining: " . substr($session_data, $offset));
            }
            $pos = strpos($session_data, "|", $offset);
            $num = $pos - $offset;
            $varname = substr($session_data, $offset, $num);
            $offset += $num + 1;
            $data = unserialize(substr($session_data, $offset));
            $return_data[$varname] = $data;
            $offset += strlen(serialize($data));
        }
            return $return_data;
    }

    private static function unserialize_phpbinary($session_data) {
        $return_data = array();
        $offset = 0;
        while ($offset < strlen($session_data)) {
            $num = ord($session_data[$offset]);
            $offset += 1;
            $varname = substr($session_data, $offset, $num);
            $offset += $num;
            $data = unserialize(substr($session_data, $offset));
            $return_data[$varname] = $data;
            $offset += strlen(serialize($data));
        }
        return $return_data;
    }
}
like image 500
Nathan Kot Avatar asked Mar 21 '13 03:03

Nathan Kot


People also ask

How are session variables encoded and decoded in PHP?

In PHP, session encodes and decode operations are automatically performed while storing session data in memory and reading stored sessions, respectively. While encoding, the $_SESSION array is converted into serialized string format and decoding reverts serialized string back to its original form.

What is encoding and decoding PHP?

However, the question is, why is it used? Encoding and decoding URL strings are used to convert general URL strings and characters into an arrangement that can be conveyed over the internet. In this tutorial, you will learn about two ways in which URL string can be encoded and decoded in PHP.

Is PHP session data secure?

“Is a PHP session secure? PHP sessions are only as secure as your application makes them. PHP sessions will allow the client a pseudorandom string (“session ID”) for them to distinguish themselves with, but on the off chance that the string is intercepted by an attacker, the aggressor can imagine to be that client.

What are the PHP sessions and how do they work?

In PHP, a session provides a way to store web page visitor preferences on a web server in the form of variables that can be used across multiple pages. Unlike a cookie, variable information is not stored on the user's computer.


1 Answers

Igbinary ( https://github.com/igbinary/igbinary/ ) is a drop in replacement for the standard php serializer. Instead of time and space consuming textual representation, igbinary stores php data structures in compact binary form. Savings are significant when using memcached or similar memory based storages for serialized data. About 50% reduction in storage requirement can be expected. Specific number depends on your data.

Unserialization performance is at least on par with the standard PHP serializer. Serialization performance depends on the "compact_strings" option which enables duplicate string tracking. String are inserted to a hash table which adds some overhead. In usual scenarios this does not have much significance since usage pattern is "serialize rarely, unserialize often". With "compact_strings" option igbinary is usually a bit slower than the standard serializer. Without it, a bit faster.

Features

  • Supports same data types as the standard PHP serializer: null, bool, int, float, string, array and objects.
  • __autoload & unserialize_callback_func
  • __sleep & __wakeup
  • Serializable -interface
  • Data portability between platforms (32/64bit, endianess)
  • Tested on Linux amd64, Linux ARM, Mac OSX x86, HP-UX PA-RISC and NetBSD sparc64
  • Hooks up to APC opcode cache as a serialization handler (APC 3.1.7+)
  • Compatible with PHP 5.2 and 5.3

Hope it helps

like image 51
Marcos Besteiro López Avatar answered Nov 14 '22 23:11

Marcos Besteiro López