PHP

PHP Session Example

Sessions are an important part not only of PHP, but of every web programming language. They are useful to access information across any page of the application, but should choose with care the data we want to save in it.

For this example, we will use:

  • Ubuntu (14.04) as Operating System.
  • Apache HTTP server (2.4.7).
  • PHP (5.5.9).

 

Tip
You may skip environment preparation and jump directly to the beginning of the example below.

1. Preparing the environment

1.1. Installation

Below, commands to install Apache and PHP are shown:

sudo apt-get update
sudo apt-get install apache2 php5 libapache2-mod-php5
sudo service apache2 restart

2. Understanding what the session is

The session is the way for the web applications, regardless the language or technology used, to have data accessible from any of the pages, without needing to pass it as parameter.

The session data is stored in the server, so, don’t confuse it with cookies, which are stored in the client.

When a user establishes a connection with a web server, a session is started. We normally associate the “session” word to the login within an application, but it does not have to involve it necessarily. Actually, the session is a temporary connection between a web server and a unique client. For this, the server generates a unique key for each client. This key is sent to the user’s browser and is stored in a cookie, to allow the server identify each client.

As its data is stored in the server, the session can be considered more secure than the cookies. But remember that the session identifier is stored in a cookie, so, the session data integrity and confidentiality will be compromised if the cookies are compromised, so we should not store sensitive information as session variable, such us passwords in plain text.

As said before, sessions have a limited lifetime. In PHP, by default, is 1440 seconds (24 minutes), but we can modify it changing the value of the session.gc_maxlifetime in the php.ini file.

3. Session in PHP

3.1. Seeing how session works

Let’s see a simple example to see how the session works:

show_session_id.php

<?php

session_start();

echo 'Your session ID is: ' . $_COOKIE['PHPSESSID'] . '<br>';

To start a session, me must call session_start() method, as in line 3.

After calling it, that session identifier will be saved in a cookie named PHPSESSID (line 5) by default. The name can be changed modifying the session.name directive in php.ini.

If we refresh the page, we will notice that the value does not change. If we open a new window with the same browser, and we follow the link, the value will not change neither. This is because, as we said above, the session identifier is saved in the client side, in the browser.

Now, if we follow that script with another browser, or with a “private window” of the same, we will see another identifier.

Note: is better to use session_name() and session_id() functions, instead of accessing directly the cookie. The first, returns the session name (PHPSESSID by default); and the second, the session identifier (the value saved in the cookie for that session name).

3.2. Saving and accessing session data

The example above was only to understand how session works, but the interesting part comes here.

The session data in PHP is saved in a superglobal object, named $_SESSION. It’s just a common associative array, as any other.

The following script shows how we can write and read values from $_SESSION:

session_handling.php

<?php

session_start();

define('ACTION_READ', 'read');
define('ACTION_WRITE', 'write');
define('WRITE_KEY', 'key');
define('WRITE_VALUE', 'value');

/**
 * Checks if the given parameters are set. If one of the specified parameters is not set,
 * die() is called.
 *
 * @param $parameters The parameters to check.
 */
function checkGETParametersOrDie($parameters) {
    foreach ($parameters as $parameter) {
        isset($_GET[$parameter]) || die("Please, provide '$parameter' parameter.");
    }
}

// Flow starts here.
echo "Your session ID is '" . session_id() . "'.<br><br>";

checkGETParametersOrDie(['action']);

$action = $_GET['action'];

switch($action) {
    case ACTION_READ:
        $response = 'Session data:<br>';

        foreach ($_SESSION as $key => $value) {
            $response .= "'$key' => '$value'<br>";
        }

        break;

    case ACTION_WRITE:
        checkGETParametersOrDie([WRITE_KEY, WRITE_VALUE]);
        $key = $_GET[WRITE_KEY];
        $value = $_GET[WRITE_VALUE];

        $response = "Saving '$value' with '$key' key into session data.";
        $_SESSION[$key] = $value;

        break;

    default:
        $response = "Please, provide a valid 'action' parameter.";
        break;
}

echo $response;

Nothing actually new: we iterate the array to get both the keys and the values (line 33), and we save new values for the given key (line 45).

We have to keep in mind that we always have to call session_start() when using the $_SESSION superglobal. Otherwise, PHP will throw a warning saying that the object is undefined.

As in a common array, if you try to save a value for an existing key, it will be overwritten.

Note: we are showing the session just for debugging purposes, the session id should never be shown.

3.3. Ending the session

When we are sure that we don’t need a session anymore, we should end it, similarly to loging an account for an application.

For that, PHP provides the session_destroy() function. Let’s add an option to allow to end the session:

session_handling.php

// ...

define ('ACTION_END_SESSION', 'end');

// ...

case ACTION_END_SESSION:
    $ended = session_destroy();

    if ($ended) {
        $response = 'Session has ended successfully.';
    } else {
        $response = 'Some problem occurred when trying to end the session.';
    }

    break;

// ...

Now, if we first follow the URL to end the session (http://localhost/path/to/session_handling.php?action=end), and then the one to read, we won’t see any session data. Seems to work.

But look at the cookie: keeps existing in the client, with the same value. Why? Because session_destroy() only wipes the session data, that is, destroys the session file generated in the server; but the cookie remains in the client. Definitely, this is not the best name for the function.

The session_destroy() function returns true or false depending on the success of the operation. Unfortunately, we can’t get more information if the function fails.

3.4. Ending the session properly

When ending a session, it does not make sense to keep the cookie in user’s browser, as session_destroy() does. So, let’s code our own function to end the session properly.

session_handling.php

/**
 * Destroys the session completely, including the cookie where the session id is stored.
 *
 * @return Value returned by session_destroy().
 */
function destroySession() {
    $_SESSION = array();
    $cookieParameters = session_get_cookie_params();

    setcookie(session_name(), '', time(), $cookieParameters['path'],
        $cookieParameters['domain'], $cookieParameters['secure'], $cookieParameters['httponly']);

    $destroyed = session_destroy();

    return $destroyed;
}

Let’s see carefully what we are doing:

  • In line 7, we wipe the $_SESSION object, re-initializing the array. session_destroy() function is supposed to do so, but, just in case.
  • In the following line, 8, we get the parameters of the cookie that saves the session. We will see later which are these parameters. To overwrite the cookie, we need to do it with the same parameters as it was created; that’s why we need them.
  • In lines 10 and 11 is where we deleting the session cookie (actually, overwriting the existing one for the session), with setcookie() built-in function. Let’s inspect each parameter:
    • The first, where session_name() is passed, is the name of the cookie itself. In this case, if we haven’t changed php.ini, it will be PHPSESSID.
    • The second, the value of the cookie. As we want to delete it, we pass an empty string.
    • The third parameter is the time the cookie expires, which is expected to be a UNIX time stamp. So, if we want to expire inmediately, we pass the current time stamp.
    • The remaining parameters are the ones used at cookie creation, which we said before that are required to overwrite the cookie.
  • Finally, in line 13, we call session_destroy(), and we return the the value returned by the function.

4. Why you shouldn’t store sensitive information in session

We have said that is not a good idea to store sensitive information in session data. You may think that it would be improbable to get a session hijacked. But, actually, hijacking a session can be easy.

The emphasis in “can be” is because not always can be easy, but yes some times, mainly because the developers do not realize the real danger that can entail.

Let’s suppose that an attacker has get the session identifier by a XSS attack. This is not as difficult as it may sound, really. We won’t see how to get the session id by an attack since it’s not the purpose of this example, but we’ll asumme that it has been compromised.

Let’s see how easy would be to hijack that session:

session_hijack.php

<?php

isset($_GET['target-session']) || die("Please, provide a 'target-session' parameter to hijack!");

echo 'This is an evil user hijacking a PHP session...<br>';

$targetSession = $_GET['target-session'];

setcookie('PHPSESSID', $targetSession);
session_id($targetSession);
session_start();

echo 'Stored data in hijacked session:<br>';

foreach ($_SESSION as $key => $value) {
    echo "'$key' => '$value'<br>";
}

echo "<h1>Don't store sensitive data in session!</h1>";

3 lines of code are enough to hijack a session, and see what is stored in it.

The only thing we are doing is to create manually the cookie with the session identifier, assuming that the session name will probably be the default name, PHPSESSID; and starting a session with the target id (the session_id() function sets the session id to the passed value).

You can test it, writing some data in the session with the example seen in previous sections, and then opening this script with another browser, passing the session id.

We said that an attacker could obtain the session id, but it could also perform a brute-force attack to try to hijack as many sessions as possible.

Have you ever thought that hijacking a session could be that easy?

Disclaimer: this is just for learning purposes, don’t try to hijack nobody’s session if you don’t want to get in trouble with law.

5. Summary

In this example about PHP sessions, we have seen how they work, understanding how they are created and how does the server know to which client correspond each session object, and the dangerous part of this, seeing why we shouldn’t store any sensitive data in session.

6. Download the source code

This was an example of PHP session.

Download
You can download the full source code of this example here: PHPSessionExample
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button