Skip to content

Handling sessions #15

@tyler-sommer

Description

@tyler-sommer

I've successfully gotten a fairly large Symfony 2 application working under FastCGIDaemon. Initial testing shows up to 400ms saved per request!

However, I ran into some issues with handling multiple simultaneous sessions. I gutted the Symfony 2 handling (other than HttpFoundation Request/Response) to try to get an understanding of how PHP is handling things. Here's what I've got so far:

<?php

require_once __DIR__ . '/../vendor/autoload.php';

use PHPFastCGI\FastCGIDaemon\ApplicationFactory;
use PHPFastCGI\FastCGIDaemon\Http\RequestInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;

$stream = fopen('php://stdout', 'w');

ini_set('session.use_cookie', false);

$kernel = function (RequestInterface $originalRequest) use ($stream) {
    $request = $originalRequest->getHttpFoundationRequest();

    fwrite($stream, $request->headers."\n");

    if ($sessId = $request->cookies->get(session_name())) {
        session_id($sessId);
    } else {
        session_id(hash('sha1', uniqid(mt_rand(), true)));
    }

    session_start();

    if (!isset($_SESSION['test'])) {
        fwrite($stream, 'Saving test!'."\n");
        $_SESSION['test'] = 'thing';
    } else {
        fwrite($stream, 'Showing test: '.$_SESSION['test']."\n");
    }

    $response = Response::create();

    $cookieParams = session_get_cookie_params();
    $response->headers->setCookie(new Cookie(session_name(), session_id(), time()+86400, $cookieParams['path'], $cookieParams['domain'], $cookieParams['secure'], $cookieParams['httponly']));

    fwrite($stream, $response->headers."\n");

    session_write_close();

    return $response;
};

$application = (new ApplicationFactory)->createApplication($kernel);
$application->run();

This works, though obviously ugly. Key points:

  • You must generate your own session ID, always. PHP seems to want to keep the last used ID if it is not explicitly overwritten.
  • You must set the cookie on the response manually. I used session_get_cookie_params() so that the ini settings could be used.

Thoughts:

  • Implementing a SessionHandlerInterface will invariably be a better solution. This also gives you a clear place to implement the regenerating of a session_id (by setting a create_sid callback [yes, that means the old session_set_save_handler prototype must be used]).
  • Disabling session.use_cookie might not be necessary

I'm concerned that I'm missing something as far as maintaining session security (preventing hijacking or fixation). Since this code blindly checks for a PHPSESSID cookie, it would be a trivial affair to hijack someone else's session, if you could guess the ID. However, I don't think this logic differs from the built-in default PHP session_id validation logic, so maybe it's a moot point.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions