Section 4.4. Session Hijacking


4.4. Session Hijacking

The most common session attack is session hijacking . This refers to any method that an attacker can use to access another user's session. The first step for any attacker is to obtain a valid session identifier, and therefore the secrecy of the session identifier is paramount. The previous sections on exposure and fixation can help you to keep the session identifier a shared secret between the server and a legitimate user.

The principle of Defense in Depth (described in Chapter 1) can be applied to sessionssome minor safeguards can offer some protection in the unfortunate case that the session identifier is known by an attacker. As a security-conscious developer, your goal is to complicate impersonation. Every obstacle, however minor, offers some protection.

The key to complicating impersonation is to strengthen identification. The session identifier is the primary means of identification, and you want to select other data that you can use to augment this. The only data you have available is the data within each HTTP request:

     GET / HTTP/1.1     Host: example.org     User-Agent: Firefox/1.0     Accept: text/html, image/png, image/jpeg, image/gif, */*     Cookie: PHPSESSID=1234 

You want to recognize consistency in requests and treat any inconsistent behavior with suspicion. For example, while the User-Agent header is optional, clients that send it do not often alter its value. If the user with a session identifier of 1234 has been using Mozilla Firefox consistently since logging in, a sudden switch to Internet Explorer should be treated with suspicion. For example, prompting for the password is an effective way to mitigate the risk with minimal impact to your legitimate users in the case of a false alarm. You can check for User-Agent consistency as follows:

     <?php     session_start();     if (isset($_SESSION['HTTP_USER_AGENT']))     {       if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT']))       {         /* Prompt for password */         exit;       }     }     else     {       $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);     }     ?> 

I have observed that some versions of Internet Explorer send a different Accept header depending upon whether the user refreshes the browser, so Accept should not be relied upon for consistency.


Requiring a consistent User-Agent helps, but if the session identifier is being propagated in a cookie (the recommended approach), it is reasonable to assume that, if an attacker can capture the session identifier, he can most likely capture the value of all other HTTP headers as well. Because cookie disclosure typically involves a browser vulnerability or cross-site scripting, the victim has most likely visited the attacker's web site, disclosing all headers. All an attacker must do is reproduce all of these to avoid any consistency check that uses HTTP headers.

A better approach is to propagate a token in the URLsomething that can be considered a second (albeit much weaker) form of identification. This propagation takes some workthere is no feature of PHP that does it for you. For example, assuming the token is stored in $token, all internal links in your application need to include it:

     <?php     $url = array();     $html = array();     $url['token'] = rawurlencode($token);     $html['token'] = htmlentities($url['token'], ENT_QUOTES, 'UTF-8');     ?>     <a href="index.php?token=<?php echo $html['token']; ?>">Click Here</a> 

To make propagation a bit easier to manage, you might consider keeping the entire query string in a variable. You can append this variable to all of your links, which makes it easy to refactor your code later, even if you don't implement this technique initially.


The token needs to be something that cannot be predicted, even under the condition that the attacker knows all of the HTTP headers that the victim's browser typically sends. One way to achieve this is to generate the token using a random string:

     <?php     $string = $_SERVER['HTTP_USER_AGENT'];     $string .= 'SHIFLETT';     $token = md5($string);     $_SESSION['token'] = $token;     ?> 

When you use a random string (SHIFLETT in this example), prediction is impractical. In this case, capturing the token is easier than predicting it, and by propagating the token in the URL and the session identifier in a cookie, multiple attacks are needed to capture both. The exception is when the attacker can observe the victim's raw HTTP requests as they are sent to your application, because this discloses everything. This type of attack is more difficult (and therefore less likely), and it can be mitigated by using SSL.

Some experts warn against relying on the consistency of User-Agent. The concern is that an HTTP proxy in a cluster can modify User-Agent inconsistently with other proxies in the same cluster.


If you do not want to depend on User-Agent consistency, you can generate a random token:

     <?php     $token = md5(uniqid(rand(), TRUE));     $_SESSION['token'] = $token;     ?> 

This approach is slightly weaker, but it is much more reliable. Both methods provide a strong defense against session hijacking. The appropriate balance between security and reliability is up to you.




Essential PHP Security
Essential PHP Security
ISBN: 059600656X
EAN: 2147483647
Year: 2005
Pages: 110

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net