Adam Innes · Blog

Firesheep Is Out. Lock Down Your PHP Sessions

· 3 min · php, security, sessions, https, firesheep

Just over a week ago, on October 24 at ToorCon 12, Eric Butler released Firesheep, a free, open source Firefox extension for Mac OS X and Windows (he says Linux support is on the way). You join a busy open Wi-Fi network, click “Start Capturing”, and as people nearby visit sites Firesheep knows about, their names and photos show up in a sidebar. Double click one and you’re logged in as that person.

None of this is new. Butler’s own write up says as much: HTTP session hijacking, which he notes is sometimes called “sidejacking”, is a widely known problem. Plenty of sites encrypt the login form but send everything after it, including the session cookie, over plain HTTP. On open Wi-Fi that cookie is readable by anyone nearby. What Firesheep changed is the effort level. It went from “know your way around a packet sniffer” to “install an add-on”.

If you run a PHP app with a login, your PHPSESSID cookie is exactly the kind of thing it grabs. Firesheep only lights up for sites it already knows about, but the underlying trick works on any site that sends a session cookie in the clear.

The real fix is HTTPS everywhere you’re logged in

I’ll say this first because the PHP settings below don’t help without it. If any page a logged in user loads goes over plain HTTP, the browser sends the session cookie with that request, and the game is over. Butler’s position is that nothing short of encrypting the entire session, HTTPS from end to end, actually fixes this. So the whole logged in experience has to be HTTPS: every page, every AJAX call, and ideally every image and script on those pages too, so browsers don’t complain about mixed content.

A common pattern is a login form posted over HTTPS that then redirects back to http://. That protects the password once and hands the session cookie to everyone at the coffee shop on the very next request. If that describes your app, that redirect is the first thing to change.

Session settings that help

Once logged in traffic is on HTTPS, tell PHP to keep the cookie there. These are all standard session runtime settings:

session.cookie_secure = 1
session.cookie_httponly = 1
session.use_only_cookies = 1

session.cookie_secure marks the cookie so the browser only sends it over secure connections. It defaults to off, and it’s the setting that directly answers Firesheep, as long as your site actually serves the logged in pages over HTTPS. If a stray HTTP link slips through, the browser just won’t attach the cookie, so the user looks logged out on that page instead of leaking their session.

session.cookie_httponly (available since PHP 5.2.0) hides the cookie from JavaScript. That doesn’t stop sniffing at all, but it takes the easy cookie theft out of an XSS bug, and it costs nothing. The manual notes not every browser supports it.

session.use_only_cookies stops PHP from accepting session IDs from the URL. It has defaulted to on since PHP 5.3.0, but if you’re on 5.2 or have old config lying around, set it explicitly.

If you can’t touch php.ini, session_set_cookie_params() takes the lifetime, path and domain first, then the secure and httponly flags as its fourth and fifth arguments. Call it before session_start().

Give users a new session ID when they log in

session_start();
if ($user = check_login($_POST['username'], $_POST['password'])) {
    session_regenerate_id(true);
    $_SESSION['user_id'] = $user['id'];
}

session_regenerate_id() swaps the current ID for a fresh one and keeps the session data. Passing true (supported since PHP 5.1.0) deletes the old session so the previous ID stops working. To be clear, this defends against session fixation, where an attacker plants a known ID before the victim logs in, not against someone sniffing the new cookie afterwards. It belongs in every login handler anyway, and it’s worth doing again when a user changes privilege level, like stepping into an admin area.

What I’d do this week

Get a certificate on every host that handles logins if you haven’t. Move the full logged in area to HTTPS and send HTTP requests for it over with a redirect. Then flip session.cookie_secure and session.cookie_httponly on, add session_regenerate_id(true) to login, and test with a browser on a network you don’t trust. Firesheep is a demonstration, but it’s a very convincing one, and your users are on that coffee shop Wi-Fi whether you like it or not.

← all posts