Using Sessions In Zend Framework 2 – Part 2

Managing Sessions in ZF2

In this tutorial, we looking further at Sessions in Zend Framework 2, specifically investigating session validators and the different backend storage options available.

In last week’s tutorial we covered the basics of sessions in Zend Framework 2, looking at how to implement them by making changes to module/Application/Module.php so that they’re available application-wide then how to both set and retrieve information in the session.

In this week’s tutorial, we’re going to take last week’s post further, by looking at session validation as well as different backends.

These two things will help protect your session data from session hijacking, as well as help you scale your application, by storing the information using a more universal backend, which a filesystem most often times will never be.

Some Session Background

Before we jump in to looking at validators and save handlers, last week’s post was a bit light on. So I want to cover a bit more about the Session classes. Firstly, using the Zend Framework 2 classes, sessions are able to be namespaced.

ZF2 Session Namespaces

 

In the standard PHP session classes, everything is in one large bucket (if you will). However, a lot like namespace support in PHP, the session data is able to be namespaced as well, by the use of Zend\Session\Container objects which are what store the Session data. This provides for a more logical order of the information contained.

Session Validators

Firstly, let’s look at the session validators. By default, Zend Framework 2 comes with 2: HttpUserAgent and RemoteAddr.

HttpUserAgent: keeps track of the User-Agent string provided by the client, usually the browser, across the requests to the session. Specifically, the classes use the $_SERVER['HTTP_USER_AGENT'] variable. If, at any time, the User-Agent string provided changes, then the request is deemed to be invalid.

This may or may not be a good validator to use. In all likelihood, a User-Agent won’t change often. But then, the people that you’re trying to protect yourself from, won’t be your average, normal, users.

RemoteAddr: keeps track of the remote IP address used by the client when interacting with the session. As with HttpUserAgent, if at any time it changes, then this is deemed to be an invalid request.

However, as the code comments state (Zend\Session\Validator\RemoteAddr.php), this isn’t necessarily a reliable check to use, as it can be easily spoofed, plus it can be prone to error if the user is sitting behind a proxy.

However, depending on your situation, it may be a worthwhile class to use. To enable both of these, I’ll update the example from last week, as below:

$this->initSession(array(
  'remember_me_seconds' => 180,
  'use_cookies' => true,
  'cookie_httponly' => true,
  'validators' => array(
    'Zend\Session\Validator\RemoteAddr',
    'Zend\Session\Validator\HttpUserAgent',
  ),
));

Alternatively, we could have configured them this way, by updating the initSession function:

public function initSession($config)
{
  $sessionConfig = new SessionConfig();
  $sessionConfig->setOptions($config);
  $sessionManager = new SessionManager($sessionConfig);
  $manager->getValidatorChain()
          ->attach(
            'session.validate',
            array(new HttpUserAgent(), 'isValid')
          )
          ->attach(
            'session.validate',
              array(new RemoteAddr(), 'isValid')
          );
  $sessionManager->start();
  Container::setDefaultManager($sessionManager);
}

By adding in the validators array, along with the two validator classes, we’ve now enabled support for both of the validators above. Nothing too hard.

Session Storage Backends

As with the Session validators, Zend Framework 2 comes with some pre-packaged storage backends; these being Cache, DbTable and MongoDB.

In the documentation, you’ll see examples of configuring each of these three, so I won’t try and rehash them here. But I will further refactor initSession, so that we have a living example:

public function initSession($config)
{
  $sessionConfig = new SessionConfig();
  $sessionConfig->setOptions($config);
  $sessionManager = new SessionManager($sessionConfig);
  $manager->getValidatorChain()
          ->attach(
          'session.validate',
            array(new HttpUserAgent(), 'isValid')
          )
          ->attach(
            'session.validate',
            array(new RemoteAddr(), 'isValid')
          );

  $cache = StorageFactory::factory(array(
    'adapter' => array(
    'name' => 'memcached',
    'options' => array(
    'server' => '127.0.0.1',
  ),
)
));

$saveHandler = new Cache($cache);
$sessionManager->setSaveHandler($saveHandler);
$sessionManager->start();

Container::setDefaultManager($sessionManager);

}

Wrapping Up

So there you have it. With not a lot of effort, we’ve seen how to quickly and simply extend an existing Session configuration in Zend Framework 2 so that we can add in support for session validation as well as use a variety of different session save handlers.

How will this enable you to write more flexible and scaleable applications?

Related Files:

  • Zend\Session\Validator\RemoteAddr
  • Zend\Session\Validator\HttpUser Agent
  • Zend\Session\SaveHandler\Cache.php
  • Zend\Session\SaveHandler\DbTableGateway.php
  • Zend\Session\SaveHandler\MongoDB.php
Sessions