Skip to content

Handling sessions #15

Open
Open
@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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions