librelist archives

« back to archive

Using Timestamps to Prevent Session Hijacking?

Using Timestamps to Prevent Session Hijacking?

From:
James Thornton
Date:
2011-06-16 @ 22:55
I have been looking at ways to guard against session-hijacking, where
someone steals a session cookie and uses it to gain access to the
system.

Programs such as http://codebutler.com/firesheep make it easy to sniff
sessions on open Wireless networks, and other ways of getting sessions
include cross-site scripting attacks, or just physically lifting them
from a victim's computer.

Using SSL to secure all session-cookie/server communications is
critical for preventing the Firesheep sniff, and setting HTTPOnly on
the cookie helps prevent JavaScript from being able to read the
session cookie in XSS attacks, but it's still vulnerable to AJAX-based
attacks.

Another layer is to include a security token or a nonce in the session
cookie that gets updated on each request. You store the token in a
server-side datastore and in the cookie, and on each request you
compare that the token in the cookie matches the token in the
datastore.

If the tokens don't match that could be an indicator that someone
stole the session and is trying to use it so you can either ignore the
request or invalidate the session and require the user to
re-authenticate. However, mismatched tokens could also result from a
slow/flaky connection.

For example, you could have a case where the server receives a request
from a real user, updates the session token in the server datastore
and responds to the user with a session cookie that contains the
updated token. But the user doesn't receive the response due to a
slow/flaky connection so the user still has the old session token
while the new one is stored on the server. When the user retries the
request, the tokens won't match.

One way to mitigate this problem is for the sever to keep a history of
the last few tokens and check that to see if they match, but then it
becomes a situation of how many tokens to keep, and depending on how
flaky the connection is or how click-happy the user is, the server may
cycle through the history before the connection comes back and the
user's session gets updated by the browser.

An alternative to keeping a token history is to timestamp each session
and check if the timestamps are within some short, specified range,
say 30 seconds. If the user's session cookie timestamp is within 30
seconds of the server's stored session timestamp, then the session is
deemed authentic.

Example pseudocode

def authenticate_request():
    if (stored_session.timestamp - session.timestamp > 30 seconds):
        return False
    return True

This avoids having to keep a token history -- the timestamp becomes
the token -- but attackers have a 30 second window of opportunity to
hijack the session after it's stolen. While this is true, the
token-history alternative isn't any better because it gives attackers
a potentially longer window of opportunity.

Other approaches of checking for IP address and User-Agent changes
have issues too. User Agents are easily spoofed, and if an attacker is
able to get a user's session, they can easily determine the User Agent
through the same XSS code or some other means.

If the user is on a mobile device, their IP address may change
frequently so that would result in many false positives. Furthermore,
the attacker could be behind the same company firewall so the user and
attacker's IP are the same to the external Web server.

Is using a timestamp token the right approach or is there a better
way? Is the 30-second buffer about right? What edge cases am I
missing?

NOTE: Using timestamps in this way does not mean that the user has to
refresh the page every 30 seconds for fear of being logged out.

Think of the timestamp stored on the session cookie as a token -- as
long as it matches the token on the server it doesn't matter how long
the token sits on the user's computer until their next request, it
just has to match.

The 30-second window is just to reduce false positives from an active
user double clicking on a slow/flaky connection. Under the normal case
of a matching token, the difference between (stored_session.timestamp
- session.timestamp) will equal zero (no difference).

Re: [flask] Using Timestamps to Prevent Session Hijacking?

From:
Sean Chittenden
Date:
2011-06-16 @ 23:31
> Is using a timestamp token the right approach or is there a better
> way? Is the 30-second buffer about right? What edge cases am I
> missing?

If a user walks away from their computer?

This isn't an easy problem, but here are some random bits that I have 
stuffed away in my head over the last decade (using an enumerated list for
referencing, these points are in any particular order of importance):

1) The only way to really prevent session fixation is to use SSL (cookie 
session hijacking).

2) HTTP and HTTPS should both have distinct session IDs.

3) When a user logs in they should have their session IDs rekeyed (new 
session ID and old session IDs should be invalidated).

4) No data attached to an HTTP session can be trusted

5) HTTPS based session data can be trusted

6) Confirm session information learned via an HTTP session via HTTPS

7) Rekeying sessions too frequently invalidates all opportunities for 
caching. Hint: Use a rekeying interval that's equal to the session 
timeout. If the user enters the last 50% of their session lifetime, rekey 
their session.

8) Don't confuse renewing a session with rekeying a session, they are two 
different windows of time.

9) An easy way to provide decent security is to use links that traverse 
HTTP and HTTPS when you want to confirm information:

   http://example.com/product/1234  -> Link to "add to cart" points to: 
https://example.com/product/1234/cart/add

   Because you have an HTTPS session that is associated with the same user
as the HTTP cookie and you can trust the HTTPS based session id, add the 
item to the cart. If the HTTPS session cookie doesn't match, invalidate 
the HTTP session.

10) PKI HTTPS infrastructure sucks to administrate, users are largely 
clueless regarding security and the result is sub-100% security, but it's 
as good as we get for the time being.

11) Using IP addresses is one way to invalidate a session, but it's a bad 
thing rely on to provide security. I tossed a few other misc recent notes 
on the subject here:

   
https://github.com/sean-/flask-skeleton/blob/master/sql/initialize/210_tables.sql#L77

12) When transiting from HTTPS to HTTP, make sure the user's browser won't
leak any potentially sensitive information via the HTTP Referer header.

13) No matter what you do, HTTP based sessions will always leave a window 
of vulnerability. Even if you change the HTTP session ID every request, a 
malicious with faster network access (e.g. a BGP MITM attack) will be able
to send a user's HTTP session back to the source faster than a user.

14) Why do you trust the server you're talking to, anyway? Ugh. Don't try 
and solve this problem unless you're really interested in crypto. Almost 
nobody does, however. :~]


Authorization is a different problem that I won't touch on here. Good enough? -sc

--
Sean Chittenden
sean@chittenden.org

Re: [flask] Using Timestamps to Prevent Session Hijacking?

From:
James Thornton
Date:
2011-06-16 @ 23:55
On Thu, Jun 16, 2011 at 6:31 PM, Sean Chittenden <sean@chittenden.org> wrote:
>> Is using a timestamp token the right approach or is there a better
>> way? Is the 30-second buffer about right? What edge cases am I
>> missing?
>
> If a user walks away from their computer?

Hi Sean -

Thanks for the reply. Yes, if the session cookie is stolen on the
user's last request to the server (i.e. the user walks away from the
browser), the stolen session will appear valid to the server.

But this should be relatively rare unless the user is being targeted
and the attacker finds a way to hose the connection so the user can't
make another request -- targeted attacks are much harder to prevent.

- James

Re: [flask] Using Timestamps to Prevent Session Hijacking?

From:
Sean Chittenden
Date:
2011-06-23 @ 21:46
> 10) PKI HTTPS infrastructure sucks to administrate, users are largely 
clueless regarding security and the result is sub-100% security, but it's 
as good as we get for the time being.

Rationale for my comment on why PKI sucks:

https://docs.google.com/present/view?id=df9sn445_206ff3kn9gs

It's replacement isn't here yet for HTTP(s), but one of these days... -sc

--
Sean Chittenden
sean@chittenden.org