Hacking PHP: Be careful with header redirects

Something I’ve noticed a lot with PHP developers is how they handle session checking for users. Most people use a simple $_SESSION['...'] check and if that fails they use a header('location:...') redirect. I’ve also noticed that a lot of those same developers miss one key security flaw: not everything respects headers. Here is a small example using cURL to demonstrate what I mean.

Insecure

<?php
session_start();

// Check for the session[user_id] param to see if the user is logged in
if(!isset($_SESSION['user_id']))
  header('location:login.php');

echo 'This is my secret page.'

//  curl http://localhost/insecure.php
//  => "This is my secret page."
?>

Less Insecure

<?php
session_start();

// Check for the session[user_id] param to see if the user is logged in
if(!isset($_SESSION['user_id']))
{
  header('location:login.php');
  echo 'Denied.';
  exit();
}
echo 'This is my secret page.'

//  curl http://localhost/less_insecure.php.php
//  => "Denied."
?>

View Gist

Such an easy fix. You can see the main difference is that less_insecure.php uses exit() to kill script execution, whereas the insecure.php doesn’t. Using exit() kills cURL before it can ignore the header() call and render the page anyway.