|
||
Session fixation attacks attempt to exploit the vulnerability of a system which allows one person to fixate (set) another person's session identifier (SID).
Most session fixation attacks are web based, and most rely on session identifiers being accepted from URLs (query string) or POST data.
Alice is a nice girl who just wants to use her bank http://unsafe/.
Unfortunately, Alice is not very security savvy.
Mallory is out to get Alice's money from the bank.
Alice has a reasonable level of trust in Mallory, and will visit links Mallory sends her.
Straight forward scenario:
http://unsafe/ accepts any
session identifier, accepts session identifiers from query string and has no
security validation. http://unsafe/ is thus not secure.
http://unsafe/?SID=I_WILL_KNOW_THE_SID". Mallory is trying to fixate
the SID to I_WILL_KNOW_THE_SID.
http://unsafe/?SID=I_WILL_KNOW_THE_SID. The usual log-on screen pops
up, and Alice logs on.http://unsafe/?SID=I_WILL_KNOW_THE_SID and
now has unlimited access to Alice's account.A misconception is that servers which only accept server generated session identifiers are safe from fixation. This is false.
Scenario:
http://vulnerable/ and checks which SID is
returned. For example, the server may respond: Set-Cookie:
SID=0D6441FEA4496C2.http://vulnerable/?SID=0D6441FEA4496C2.SID=0D6441FEA4496C2.Another session fixation attack,
cross-site cooking, exploits
browser vulnerabilities. This allows a site http://evil/ to
store cookies on browser in the cookie domain of another server
http://good/, that is trusted. In order for this attack to succeed there
is no need for any vulnerability within http://good/, as
http://good/ may assume browser cookie management is secure.
Scenario:
http://evil/".http://evil/, which will cookie SID
with value I_WILL_KNOW_THE_SID into the domain of
http://good/.http://good/".Session identifiers in URL (query string, GET variables) or POST variables are not recommended as it simplifies this attack - it is easy to make links or forms which sets GET / POST variables.
Additionally, session identifiers (SID) in query string enables other risk / attack scenarios as well;
The session identifier is on most modern systems by default stored in an HTTP cookie which has a moderate level of security.
However, session identifiers are often accepted from GET/POST as well on these standard systems. Browser configuration must be modified in order to protect against this vulnerability.
For PHP, if you have access to PHP configuration, use this: php.ini:
; 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
When enabling HTTPS security, some system will 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 identifier may only be suitable for critical applications such as large financial sites due to the size of the system. It is however an issue rarely debated even in security forums.
A countermeasure against session fixation is to generate a new session identifier (SID) on each request. Thus, although attacker may trick a user into accepting a known SID, the SID will be invalid when attacker attempts to re-use the SID. Implementation of such a system is simple, as demonstrated by the following:
OLD_SID from HTTP request.OLD_SID is null, empty, or no session with SID=OLD_SID
exists, create a new session.NEW_SID with a secure
random number generator.NEW_SID (and no longer by
SID=OLD_SID)Example:
If Mallory successfully tricks Alice into visiting
http://victim/?SID=I_KNOW_THE_SID, this HTTP request is sent to
victim:
GET /?SID=I_KNOW_THE_SID HTTP/1.1 Host: victim
victim accepts SID=I_KNOW_THE_SID, which is bad.
However, victim is secure because it performs session regeneration.
victim sends the following response:
HTTP/1.1 200 OK Cookie: SID=3134998145AB331F
Alice will now use SID=3134998145AB331F which is unknown to
Mallory, and SID=I_KNOW_THE_SID is invalid. Mallory is thus
unsuccessful in the session fixation attempt.
Unfortunately session regeneration is not always possible. Known cases where session regeneration may cause problems include when third party software such as ActiveX, Java Applets, or browser plugins communicate with the server as well. Third party software could cause logouts, or the session could be split into two separate sessions.
One way to improve security is to not accept session identifiers not generated by server.
if (!isset($_SESSION['SERVER_GENERATED_SID'])) {
session_destroy(); // destroy all data in session
}
session_regenerate_id(); // generate a new session identifier
$_SESSION['SERVER_GENERATED_SID'] = true;
xcv
A logout function is useful as it allows users to indicate that a session should not allow further requests. Thus attacks can only be effective while a session is active.
if (isset($_GET['LOGOUT'])) session_destroy(); // destroy all data in session
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 they may have left unattended.
Store a session variable containing a time stamp of the last access made by that SID. When that SID is next used compare the current timestamp (in PHP you can get this by using the time() function call) 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.
When visiting a page, most browsers will set the Referrer - from which page did you click to get to this page?
When using a site which you are logged into, if the site should rarely be linked to (e.g., banking websites, webmails), and/or the session should not last too long as the user might run into links to the site, it is usually highly suspicious if the Referrer is not from within the site.
For example, http://vulnerable/ may employ the following
security check:
if (strpos($_SERVER['HTTP_REFERER'], 'http://vulnerable/') !== 0) {
session_destroy(); // destroy all data in session
}
session_regenerate_id(); // generate a new session identifier
One way to further improve security is to ensure that it 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 network begin to conform to RFC 3704 and other anti-spoofing practices, IP numbers are more reliable as a "same source" identifier. Therefore, by verifying that the source IP is consistent throughout a session, the security of a web site can be improved.
This could be performed in this manner:
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 things to consider before employing this approach.
For some sites, the added security outweighs the lack of convenience, and, for others, it does not.
Browsers identify themselves by "User-Agent" HTTP headers. This header does not normally change during use; it would be extremely suspicious if that were to happen. A web application might make use of User-Agent detection in attempt to prevent malicious users from stealing sessions. This is Security through obscurity, which has its uses, but should not be used as a single defence.
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'];
Defense in depth is to combine several countermeasures. The idea is simple: if one obstacle is hard to overcome, several obstacles could be very hard to overcome.
A DiD strategy could involve:
The following PHP script demonstrates some such countermeasures put together in a Defence in Depth manner:
if (strpos($_SERVER['HTTP_REFERER'], 'https://DiD/') !== 0) session_destroy(); if (isset($_GET['LOGOUT'])) session_destroy(); if ($_SERVER['REMOTE_ADDR'] !== $_SESSION['PREV_REMOTEADDR']) session_destroy(); if ($_SERVER['HTTP_USER_AGENT'] !== $_SESSION['PREV_USERAGENT']) session_destroy(); session_regenerate_id(); // generate a new session identifier $_SESSION['PREV_USERAGENT'] = $_SERVER['HTTP_USER_AGENT']; $_SESSION['PREV_REMOTEADDR'] = $_SERVER['REMOTE_ADDR'];
Web Design & Development Guide, Powered by Usefulref