How to generate PHP sessions securely
When conducting a web security assessment against a web application, one of the attack paths is session management. The possibility that someone can impersonate another user, or interact with application modules without being authenticated can cause headaches for developers and the organization.
There are several complex aspects of session management, but all this starts to become simpler if we centralize all the code responsible for this management in a single module. Once we have defined the file that will be the central repository of the session management functions, it is necessary to include this module in all our web pages.
Depending on our development framework, the inclusion of these functions will be done through “autoload” methods, through require() / include(), or other mechanisms enabled for module loading.
Our code must ensure that a session is initialized on each HTTP request. We are going to use for this example the security.php file that will be loaded by all the modules of the web application through the methods mentioned in the previous paragraph.
/* We initialize the session*/
session_start();
If we want to ensure the privacy of our pages, and that they indicate that they should not be cached by any intermediate proxy, we can include the following directives.
/* We state that pages cannot be cached. */
header("Expires: Tue, 01 Jul 2001 06:00:00 GMT");
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");
At this point, in which the user’s session has been initialized on the server, and that the session information has been transmitted to the user through a cookie, we must define somewhere in our application a function that is responsible for destroying the user’s session. This function has to be called from several places, being the fundamental one the logout.php page of our application (or the method used to disconnect the user), as well as the login.php page, since we will consider that any user that accesses this page wants to log in to the software, and we must invalidate his previous credentials.
function logOut() {
session_unset();
session_destroy();
session_start();
session_regenerate_id(true);
}
To destroy a session in php we must delete all the variables in the global array $_SESSION by calling session_unset(). The call to session_destroy() will delete all the information associated with the session on the server. After invalidating the previous session, we will create a new session containing a new session identifier with session_regenerate_id(). These steps will ensure that the previous session is completely invalidated.
A session fixation attack is one in which a user is able to steal another user’s session and impersonate his identity. To protect ourselves from such attacks, a first approach we should take after initializing the user’s session is to store certain session variables with client information:
$_SESSION
['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
$_SESSION['SKey'] = uniqid(mt_rand(), true);
$_SESSION['IPaddress'] = ExtractUserIpAddress();
$_SESSION['LastActivity'] = $_SERVER['REQUEST_TIME'];
In our scenario, the two most important fields are the IP of the user making the HTTP request, and the version of his browser. For activity control purposes, we will also store the date on which the request is made to the web server.
To protect ourselves from such attacks what we must check in each request is that there are no modifications in the browser parameters (IP, browser), since this would mean that someone from a different location than the user’s previous one is trying to impersonate him. The date of the last activity must not exceed a threshold defined by us, such as 120 minutes. In the event of a change in any of the above parameters, or if the user’s session has expired while accessing the web server, we must immediately call the logOut() method and exit with an exit();
Access from mobile devices can disrupt plans for comprehensive IP address control. An alternative approach may be to ignore the ip change if it has occurred from a mobile device, identifiable by the browser’s User Agent. In the future we will talk about additional geolocation-based control and additional heuristic rules to determine if the user on the other side of the connection is really who he was supposed to be at the beginning.
We have already taken away a number of problems to avoid annoying attacks against the user’s session so let’s go with one last additional recommendation to protect a web application against attacks from unauthenticated users. .
Let’s imagine that our website has several pages that must be accessed anonymously, such as login.php , register.php and logout.php, and that after authenticating the user sets a session variable $_SESSION[‘registered’] = 1 and starts accessing a number of protected resources;
At the end of our security.php script we can check for session information, so in case the user is not registered in the application ( $_SESSION['registered']
) and the page accessed is not one of those mentioned in the previous point, a call to exit() must be made. This way, an unauthenticated user will not be able to execute any system script.
And you may ask, what is $_SESSION['SKey']?
for? Well, to avoid CSRF attacks.
Discover our work and cybersecurity services at www.tarlogic.com