PHP sessions are notoriously easy to hack.

There are two primary attacks that you must guard against for your app to be considered even partially secure: [Season Hijacking](http://en.wikipedia.org/wiki/Session_hijacking Session Hijacking) [Cross Site Request Forgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery Cross-Site Request Forgery)

This lesson will show you one trick to greatly guard against both.

The Attacks

Session Hijacking

Session hijacking is ridiculously easy for a trained hacker to achieve. All one has to do is find the PHP_SESSID cookie in the victim’s browser, copy it into their own browser, and voila! With default PHP sessions, they’ve already hacked into the user’s account, no username/password required.

CSRF

CSRF is a bit more complicated, but it basically works by the same mechanism: The server gets confused and believes the hacker is an already-authenicated user.

How to guard against these? This tutorial will show you one fairly straightforward way. The file we will be modifying is (https://github.com/hopeseekr/multiauth)

Basic Guard: Giving the User a Secret

Step 1: Modify the Login form

First, modify the login form to convey a secret. This secret should be very random.

Pointers: * Your secret should be different with each login attempt. * You should have X number of secrets for X login forms. * You should never ever name the secret form value “secret” or something else that’d be searchable by hackers. Why make it easy? * The secret name should be the unique per app.

A good login form will look something like this:

<form method="post">
    <input type="hidden" name="a5##d" value="50087c0e74c2750087c0e74c5f"/>
    <input type="text" name="username"/>
    <input type="password" name="password"/>
    <input type="submit" name="login" value="Log in"/>
</form>

Step 2: Store the Secret in the Session

The second step is to start a user session and dump these into the session array. Just incase a CSRF is in progress, you shouldn’t name this something like “secret” or the name of your HTML form hidden name, either. The same 1-4 rules above apply. I’ve chosen to do this:

$authSecrets = createAuthSecrets(2);
$_SESSION['a444d'] = $authSecrets;

Step 3: Validate The User

The third step is to programmatically confirm that the user has the same secret in their session as they do in the POST form. Feel free to use the code below:

// Copyright (c) 2012 PHP Experts, Inc. 
// License: Creative Commons Attribution License v3.0 U.S.
// See: http://creativecommons.org/licenses/by/3.0/us/
function validateSession()
{
    $isValid = false;
    // See if the session has been started.
    if (!isset($_POST['login']) && empty($_SESSION))
    {
        return true;
    }

    if (isset($_POST['login'] && isset($_POST[FORM_AUTH_KEY]))
    {
        // See if the secrets match.
        if (isset($_SESSION[SESSION_AUTH_KEY]) && $_SESSION[SESSION_AUTH_KEY] == $_POST[FORM_AUTH_KEY])
        {
            $isValid = true;
        }
    }

    if ($isValid)
    {
        return true;
    }

    session_destroy();
    return false;
}

Step 4: Prohibit Non-Validating Access Attempts

The fourth, and final, step, is to blow up the app if these things don’t match:

if (!validateSession())
{
    throw new RuntimeException("You do not have the right authorization to be here");
}

End Result

The final implementation can be seen on the following page.

Additional Security Measures

This guide has only brushed the surface of all that can be done to ensure secure sessions.

Additional security measures you should consider if your app’s security is critical are

  • Store the user’s IP address along with the auth secret and validate against both. This won’t work in instances where users bounce across multiple IPs (notably: Australian, Chinese and AOL users) and has limited practicality where many users share the same IP (large corporations, etc.). This decreases the success chances of Session Hijacking attacks.
  • Encrypt the entire _SESSION object, using the user’s password and a secret key only the server knows as the password. This greatly decreases the success chances of CSRF attacks.
  • Display the secret auth token to the user and have them type it in regularly. This will prevent automatic attacks for the most part, of all types. Optionally, have a 3rd party domain present the info to the user.