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).
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.
- 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
- 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.
You can download the full source code of this example here: PHPSessionExample