Recently i wrote two other security article on XSS and SQL Injection. I find many interesting facts and solutions on those topic that i research about and wanted to know more about other security measure. Thus, in this article i will discuss on different type of session attacks and how we can better protect ourselves against these attacks to better secure our web portal.
Session attack is nothing more than session hijacking. The most important information in session attack is to obtain a valid valid session identifier (SID). There are three common methods used to obtain a valid session identifier.
- Session Prediction
- Session Capture
- Session Fixation
Session Prediction
Prediction refers to guessing a valid session identifier. With PHP's native session mechanism, the session identifier is extremely random. Hence, it is difficult to guess such SID. Although it is not the weakest point of a secure website. There are still chances of accessing the site through this method.
Solution To Session Prediction
Use of a longer random number or string as the session key. This reduces the risk that an attacker could simply guess a valid session key through trial and error or brute force attacks.
Session Capture
Capturing a valid session identifier is the most common type of session attack. Rather than predicting a correct session identifier is much easier. This approach is also known as Session Sidejacking, where the attacker uses packet sniffing to read network traffic between two parties to steal the session cookie. Unsecured Wi-Fi hotspots are particularly vulnerable, as anyone sharing the network will generally be able to read most of the web traffic between other nodes and the access point.
Solution To Session Capture
Encryption of the data passed between the parties; in particular the session key. This technique is widely relied-upon by web-based banks and other e-commerce services, because it completely prevents sniffing-style attacks. However, it could still be possible to perform some other kind of session hijack. Many web application apply SSL only on login page where session id can still be sniff out on subsequence pages. The password of such application is protected but not the session.
Session Fixation
Session fixation attacks attempt to exploit the vulnerability of a system which allows one person to fixate another person's session identifier (SID). Most session fixation rely on session identifiers being accepted from URLs (query string) or POST data.
Scenario Of Session Fixation Attacks
Here are some ways session fixation can be launched.
Simple Attack
The most simple way of an attack that can be launched due to website vulnerability.
- Attacker A knows http://unsafe.com is an unsafe site that accept SID directly through query string and no validation is being done on the site.
- Attack A send an email to Victim B 'Someone tried to access your bank account. Please access your account at http://unsafe.com?SID=H2SK9XSU1fL197DQ621Sh to change your password.' Attacker A is trying to fixate the SID to H2SK9XSU1fL197DQ621Sh.
- Victim B clicked on the URL provided and was bought to the login site.
- Victim B logged in with his access and tried to verify.
- Attack A then used the same URL to gain Victim B access since the session has been fixed to H2SK9XSU1fL197DQ621Sh.
Server Generated SID Attack
Misconcept of server generated session identifier is safe from fixate. Unfortunately not.
- Attacker A visits http://unsafe.com/ and checks which SID is returned. For example, the server may respond: Set-Cookie: SID=9AS82120DK8E0DI.
- Attacker A send in an email to Victim B. 'Please join our latest promotion at 'http://unsafe.com?SID=9AS82120DK8E0DI'.
- Victim B logged in and caused the fixate on 9AS82120DK8E0DI. Finally, Attacker A enters the same URL to gain unauthorizes access.
- Typically the same way as simple attack. The only differences is that the session identifier is being created by the server instead of the unsecured one.
Cross-Site Cooking Attack
Cross-site cooking is a type of browser exploit which allows a site attacker to set a cookie for a browser into the cookie domain of another site server. It exploits browser vulnerabilities although the original site was secure.
- Attacker A sends Victim B an e-mail: "Hey, celina has recommend you a new site at http://unsafe.com/"
- Victim B visits http://unsafe.com/, which sets the cookie SID with the value H2SK9XSU1fL197DQ621Sh into the domain of http://safe.com/
- Victim B then receives an e-mail from Attacker A, "Due to new implementation we will required you to login to http://safe.com/ to verify your bank account".
- Once Victim B logs on, Attacker A can use her account using the fixated session identifier.
Cross-Subdomain Cooking Attack
This is the same thing as cross site cooking, except that it does not rely on browser vulnerabilities. Rather, it relies on the fact that wildcard cookies can be set by one subdomain that affect other subdomains.
- A web site such as www.blogprovider.com hands out subdomains to untrusted third parties
- Attacker A who controls evil. blogprovider.com, lures Victim B to his site
- A visit to evil.blogprovider.com sets a session cookie with the domain .blogprovider.com on Victim's B browser
- When Victim B visits www.blogprovider.com, this cookie will be sent with the request, as the specs for cookies states, and Victim B will have the session specified by Attacker A cookie.
- If Victim B now logs on, Attacker A can use her account.
Victim B can be a administrator on blogprovider.com/administrator.
Each session attack scenario has resulted in Privilege escalation or Cross-calation which exploit a bug or flaw in the system to gain unauthorizes access. Such attacks are dangerous as Attack A can spy on Victim B on whatever he is doing on the system. If Victim B decides to purchase something on this site and enters her credit card details, Attack A may be able to harvest Victim B history access to see such sensitive data and details.
Session Fixation Attack
In order to better illustrate session fixate, we will consider the following example,
<?php session_start(); if (!isset($_SESSION['visits'])) { $_SESSION['visits'] = 1; } else { $_SESSION['visits']++; } echo $_SESSION['visits']; ?>
The above state that every different browser or new cookie session should have a start index of '1'. To demonstrate session fixation, first make sure that you do not have an existing session identifier, then visit this page with domain.com?PHPSESSID=1234. Next, with a completely different browser (or even a completely different computer), visit the same URL again with domain.com?PHPSESSID=1234. You will notice that the output show 2 instead of 1 because the session was continue! This is session fixate where the same session is used to continue previous session although you were not the first initializer.
Solutions To Session Fixation Attacks
Although Session Fixation is widely used. There are also many solutions for such attacks.
Do not accept session identifiers from GET / POST variables
We know from XSS attack article that global variable is dangerous. Session Fixation is one of the live example of such danger. We are all aware from this article that session fixation is achieve through query string or POST variable. Thus, prevent using such method for SID one of the best solution you can undertake to prevent simplify attack.
Additionally, such usage also increase the risk of:
- SID is leaked to others servers through the Referrer
- SID is leaked to other people through communication channels and social network
- SID is being stored in many places (browser history log, web server log, proxy logs, ...)
Change Important Session identifier
Session Fixation can be largely avoided by changing the session ID when users log in. In every important event, changing the session identifier will prevent attackers from accessing these important event. When the victim visits the link with the fixed session id, however, they will need to log into their account in order to do anything "important" as themselves. At this point, their session id will change and the attacker will not be able to do anything "important".
Store session identifiers in HTTP cookies
The session identifier on most modern systems is stored by default in an HTTP cookie, which has a moderate level of security. However, modern systems often accept session identifiers from GET/POST as well. The web server configuration must be modified to protect against this vulnerability.
; Whether to use cookies. session.use_cookies = 1 ; This option enables administrators to make their users invulnerable to ; attacks which involve passing session ids in URLs; defaults to 0. session.use_only_cookies = 1
Utilize SSL / TLS Session identifier
When enabling HTTPS security, some systems allow applications to obtain the SSL / TLS session identifier. Use of the SSL/TLS session identifier is very secure, but many web development languages do not provide robust built-in functionality for this.
SSL/TLS session identifiers may be suitable only for critical applications, such as those on large financial sites, due to the size of the systems. This issue, however, is rarely debated even in security forums.
Regenerate SID on each request
Similar to 'Change Important Session identifier', however, this will regenerate the session identifier every single time a page is being request. This will further enhance the security since every single request by the user will eventually change the session identifier. Even if someone were able to capture session identifier through sniffing, the session id will eventually change which will make attacks difficult.
Accept only server generated SIDs
One way to improve security is not to accept session identifiers that were not generated by the server. Making life difficult for attacker is also one of the most important way of improve security.
#remove any session that may exist if (!isset($_SESSION['SERVER_GENERATED_SID'])) { session_destroy(); } #generate a new session id through built-in function session_regenerate_id(); $_SESSION['SERVER_GENERATED_SID'] = true;
Logout function
Session Fixation will only be active when the known session identifier is the same. Thus, the attacker known session identifier will be invalid when the user logout themselves. Hence, having the following function is critical to improve session security.
if (isset($_POST['LOGOUT'])) session_destroy(); // destroy all data in session
Time-out Session Identifier
Another very critical process of securing a web application is to implement a time out function to destroy the session whenever a session has expired. A session will expired after a given time. This defense is simple to implement and has the advantage of providing a measure of protection against unauthorized users accessing an authorized user's account by using a machine that may have been left unattended.
Store a session variable containing a time stamp of the last access made by that SID. When that SID is used again, compare the current timestamp with the one stored in the session. If the difference is greater than a predefined number, say 5 minutes, destroy the session. Otherwise, update the session variable with the current timestamp.
Destroy session if Referrer is suspicious
As mention on the scenario of session fixation, cross site cooking required an access to a bad URL and set the cookie session to the real URL. Destorying the session will prevent such attack from happening.
#check whether the referer is from our domain. if (strpos($_SERVER['HTTP_REFERER'], 'http://mywebsite.com/') !== 0) { session_destroy(); // destroy all data in session } session_regenerate_id(); // generate a new session identifier
Verify IP
One way to further improve security is to ensure that the user appears to be the same end user (client). This makes it a bit harder to perform session fixation and other attacks. As more and more networks begin to conform to RFC 3704 and other anti-spoofing practices, the IP address becomes more reliable as a "same source" identifier. Therefore, the security of a web site can be improved by verifying that the source IP is consistent throughout a session.
if($_SERVER['REMOTE_ADDR'] != $_SESSION['PREV_REMOTEADDR']) { session_destroy(); // destroy all data in session } session_regenerate_id(); // generate a new session identifier $_SESSION['PREV_REMOTEADDR'] = $_SERVER['REMOTE_ADDR'];
However, there are some points to consider before employing this approach.
- Several users may share one IP. It is not uncommon for an entire building to share one IP using NAT.
- Inconsistent IP as the users are behind proxies (such as AOL customers) or from mobile/roaming.
User Agent
Although the attacker may be able to change the user agent to match the one on the session. However, it makes the process even more difficult and may help prevent some attacker from penetrating through the session. A web application might make use of User-Agent detection in attempt to prevent malicious users from stealing sessions.
#check whether the stored agent is similar to user agent if ($_SERVER['HTTP_USER_AGENT'] !== $_SESSION['PREV_USERAGENT']) { session_destroy(); // destroy all data in session } session_regenerate_id(); // generate a new session identifier $_SESSION['PREV_USERAGENT'] = $_SERVER['HTTP_USER_AGENT'];
Full Defense
Creating multiple layer of defense mention above into a fully functional method to be used in every session authentication.
function validate_session($url) { if (strpos($_SERVER['HTTP_REFERER'], $url) !== 0 || isset($_GET['LOGOUT']) || $_SERVER['REMOTE_ADDR'] !== $_SESSION['PREV_REMOTEADDR'] || $_SERVER['HTTP_USER_AGENT'] !== $_SESSION['PREV_USERAGENT']) session_destroy(); #time-out logic session_regenerate_id(); // generate a new session identifier $_SESSION['PREV_USERAGENT'] = $_SERVER['HTTP_USER_AGENT']; $_SESSION['PREV_REMOTEADDR'] = $_SERVER['REMOTE_ADDR']; }
Other Attacks
Cross-site scripting, where the attacker tricks the user's computer into running code or link which is treated as trustworthy because it appears to belong to the server, allowing the attacker to obtain a copy of the cookie or perform other operations.
Alternatively, an attacker with physical access can simply attempt to steal the session key by, for example, obtaining the file or memory contents of the appropriate part of either the user's computer or the server.
Summary
Session attacks are common among the attack used on secure website. Effort has to be made to improve session security to prevent any thief from happening. The solutions above might not be full bullet proof solution for future session attacks. Nonetheless, it can be used for discussion on solutions of future such attack.
I sort of wrote something the other day about this. Here's my code:
'session key');
/**
* Functions
*/
/**
* FUNCTION SHA512_encode
* Return a BASE 64 encoded SHA-512 encryted string
*
* @param string $str
* @return string
*/
function SHA512_encode($str)
{
return base64_encode(bin2hex(hash('sha512',$str)));
}
// Start the session
session_start();
// Check for possible session hijacking by comparing the browser's
// User Agent to the one stored in a session. We store this in the session
// with a random text key "aszIy09" for obscurity purpouses and the data stored
// in the element is an encrypted User Agent string with a salt to help further
// prevent session hijacking.
//
// We could have also have named the element that look like some other data
// that didn't have anything to deal with User Agent information.
if(isset($_SESSION['aszIy09']) &&
$_SESSION['aszIy09'] !==
SHA512_encode($_SERVER['HTTP_USER_AGENT'].$config['salts']['sessions']))
{
// A possible session hijacking has been detected.
// Check if a cookie assocated to the session.
if(isset($_COOKIE[session_name()]))
{
// Kill the cookie assocated to the session.
setcookie(session_name(), '', time()-42000, '/');
}
// Destroy the session itself.
session_destroy();
// Start a new session.
session_start();
}
// Check if this is new session
if(!isset($_SESSION['aszIy09']))
{
// New session detected
// Load with encoded HTTP_USER_AGENT
$_SESSION['aszIy09'] = SHA512_encode($_SERVER['HTTP_USER_AGENT'].
$config['salts']['sessions']);
// Set number of loads to 0 in the session
$_SESSION['loads'] = 0;
}
// Increment the loads
++$_SESSION['loads'];
// Regenerate the session after Nth loads
// This can be over ridden if the $config['regenSession'] is set to 0
if(isset($config['regenSession']) && $config['regenSession'] > 0 &&
$_SESSION['loads'] >= $config['regenSession'])
{
// Save old session data. CYA measure.
$oldSession = $_SESSION;
// Regenerate the session id.
session_regenerate_id();
// Move old data to new session. CYA measure.
$_SESSION = $oldSession;
// Reset load count
$_SESSION['loads'] = 1;
}
// Output the session id
echo 'SESSION ID: '.session_id();
Opps:
// An example of how to secure your sessions
// Normally the config data would be an external file
$config = array();
// Set the number of loads which you want to regenerate a session id.
// Set this value to 0 if you do not want to regenerate a session id.
$config['regenSession'] = 3;
// Salts for encryption
$config['salts'] = array('sessions' => 'session key');
/**
* Functions
*/
/**
* FUNCTION SHA512_encode
* Return a BASE 64 encoded SHA-512 encryted string
*
* @param string $str
* @return string
*/
function SHA512_encode($str)
{
return base64_encode(bin2hex(hash('sha512',$str)));
}
// Start the session
session_start();
// Check for possible session hijacking by comparing the browser's
// User Agent to the one stored in a session. We store this in the session
// with a random text key "aszIy09" for obscurity purpouses and the data stored
// in the element is an encrypted User Agent string with a salt to help further
// prevent session hijacking.
//
// We could have also have named the element that look like some other data
// that didn't have anything to deal with User Agent information.
if(isset($_SESSION['aszIy09']) &&
$_SESSION['aszIy09'] !==
SHA512_encode($_SERVER['HTTP_USER_AGENT'].$config['salts']['sessions']))
{
// A possible session hijacking has been detected.
// Check if a cookie assocated to the session.
if(isset($_COOKIE[session_name()]))
{
// Kill the cookie assocated to the session.
setcookie(session_name(), '', time()-42000, '/');
}
// Destroy the session itself.
session_destroy();
// Start a new session.
session_start();
}
// Check if this is new session
if(!isset($_SESSION['aszIy09']))
{
// New session detected
// Load with encoded HTTP_USER_AGENT
$_SESSION['aszIy09'] = SHA512_encode($_SERVER['HTTP_USER_AGENT'].
$config['salts']['sessions']);
// Set number of loads to 0 in the session
$_SESSION['loads'] = 0;
}
// Increment the loads
++$_SESSION['loads'];
// Regenerate the session after Nth loads
// This can be over ridden if the $config['regenSession'] is set to 0
if(isset($config['regenSession']) && $config['regenSession'] > 0 &&
$_SESSION['loads'] >= $config['regenSession'])
{
// Save old session data. CYA measure.
$oldSession = $_SESSION;
// Regenerate the session id.
session_regenerate_id();
// Move old data to new session. CYA measure.
$_SESSION = $oldSession;
// Reset load count
$_SESSION['loads'] = 1;
}
// Output the session id
echo 'SESSION ID: '.session_id();
I recently came across your blog and have been reading along. I thought I would leave my first comment. I don't know what to say except that I have enjoyed reading. Nice blog. I will keep visiting this blog very often.
Susan
http://dclottery.info
gald you like it 🙂
appreciate your comment here!
Clay
The UA in the session is a good choice but I would suggest you hash it with salt; much like passwords you don't store nor use them in plain text form...
The same goes for your session tokens, such as UA - hash and salt them just to be sure; you can spoof a UA if it's known, but you can't if it has been hashed and salted.
Makes no difference at the end of day regards to implementation so don't use tokens in their plain vanilla form.
Les, that's very true.