3

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?

espeed
  • 4,754
  • 2
  • 39
  • 51

1 Answers1

2

I don't see how a timestamp would work. It would require the user to never spend more than 30 seconds on a page before sending another request to the server. I'm sure I spent a lot more than 30 seconds reading this page and typing up this response before pressing "Post".

It seems to me that there's an inherent problem that any data you send over the line could be intercepted and duplicated. Encryting a password doesn't solve the problem, because a hacker could intercept the encrypted value and then send that encrypted value. He doesn't necessarily care what the unencrypted value is.

Same story for any token you send. The hacker could intercept the token and duplicate it.

The only idea I've heard that seems to solve the problem is a challenge-and-response system using public and private keys: A creates a random character string, encrypts it using B's public key, and sends it to B. B decrypts that string using his private key and sends the decrypted value back along with his application data. A then validates that the decrypted value matches the original value. If it doesn't validate, he rejects the associated data.

A hacker can't intercept the message from A and spoof the response if he doesn't know B's private key. A hacker can't use a previosly-intercepted reply from B because the random string is different every time.

Jay
  • 26,876
  • 10
  • 61
  • 112
  • It doesn't require them to reload the page every 30 seconds -- they can be gone for any length of time. What's important is that the timestamp in their session matches the timestamp stored on the server on the next request. – espeed Jun 16 '11 at 21:19
  • And yes, any unencrpyted data could be intercepted and duplicated, but unless they intercept the session from the last request the user makes, the token/timestamp will have been updated on the user's next request so the intercepted token will not be valid. The only time it will be valid is if they are able to intercept and use it within the 30-second window of the user's last request. – espeed Jun 16 '11 at 21:27
  • I guess I don't understand what time your timestamp represents then, and what you are comparing it too. I just reread your original post and you say "timestamp each session". But the time of what? When it was created? When you last sent a page to the user? Etc. In any case, you say this timestamp would be sent back to the server. But then anyone sniffing the line could see the session id and the timestamp. I don't see what you've gained. Anyway, I think you need to clarify what you're up to a little more. – Jay Jun 17 '11 at 19:54
  • A session cookie consists of a user_id, session_id, and a timestamp in an AES encrypted bundle with a SHA-1 signature. When the user logs in, the session is created and the cookie is timestamped. When the Web application responds to each request, the session cookie is updated with a new timestamp and a server-side datastore is also updated with the same info (user_id, session_id, timestamp). – espeed Jun 18 '11 at 22:51
  • So after the page loads, there will be an encrypted session cookie in the user's browser with a timestamp of let's say 12345678 and the server will also have record of the stored session and its last timestamp of 12345678. On the next request, the server will check that the user's session cookie timestamp matches the session timestamp that is stored on the server. – espeed Jun 18 '11 at 23:19
  • If they match, the request is deemed authentic. If they don't, it could be a sign that an attacker had stolen a session cookie and is trying to use it, but the server won't authenticate the request because the attacker's stolen session cookie has an old timestamp. Unless the attacker manages to steal the session cookie on the user's last request, the user will have made another request and updated the timestamp so previous session cookies will not be valid. – espeed Jun 18 '11 at 23:19
  • Hmm, okay. That guards against a hacker intercepting the message from the client to the server. It doesn't guard against a hacker intercepting the message from the server to the client, as long as he got his response back before the "legitimate" client. Also, if the client opens multiple windows within one session, it wouldn't work. Though I guess you could say that's not allowed. – Jay Jun 20 '11 at 13:25
  • If you're sending the timestamp from the server, I don't know why you'd give a 30-second window, or any window at all. The client should have the exact value sent from the server. – Jay Jun 20 '11 at 13:27
  • If you're talking about putting encryptian on the message in addition to or distinct from the encryptian you get with HTTPS, this would mean that you'd have to override the normal handling of session ids done by the client and the server. But I suppose that's not an insurmountable obstacle. If you're thinking you'd let the systems exchange the session id in the usual manner and then this would be an additional message, that would probably be a bad idea, because a hacker could see the unencrypted session id and would have that information to help him in decrypting the encrypted ... – Jay Jun 20 '11 at 13:30
  • ... message. But this would be a trivial problem: just have a different session identifier, unrelated to the J2EE session id. – Jay Jun 20 '11 at 13:31
  • A session is shared between multiple browser tabs so this shouldn't be a problem. If the user opens a new tab/browser in incognito mode, then the browser will ask them to login in again b/c it can't read their session to authenticate their identity, and then when they login they will have two separate sessions going, each with a unique token/timestamp so multiple sessions isn't a problem either. – espeed Jun 23 '11 at 21:49
  • Regarding using timestamps and a 30-second window, consider the case where the user requests a page from the server, the server updates the session timestamp/token and returns it in the response, but the connection between the user and the server is slow/flaky. If a impatient/click-happy user gets tired of waiting and sends another request by reloading the page before receiving the response from the server, then they will be sending the old token/timestamp and it won't match because the server updated it on the previous request attempt, even though the user hadn't received it yet. – espeed Jun 23 '11 at 21:53
  • While SSL will protect sessions from being sniffed in transit, it doesn't protect sessions that are stolen in cross-site scripting (XSS) attacks. If the server encrypts the session data or at least signs the plaintext session data with something like a SHA-1 or MD5 signature, the server can be reasonably sure that session data hasn't been tampered with or changed by a man-in-the middle attacker. – espeed Jun 23 '11 at 22:09
  • Most XSS attacks are of the form where an attacker manages to insert a bit of JavaScript on a Web page through a form, and the JavaScript code steals any user's session data that tries to load that page. The attacker's code then the user's session data to an external server and then the attacker tries to use the session cookie to gain access as that user. It is not a case where the attacker is intercepting server responses and then sending them back to the user. – espeed Jun 23 '11 at 22:13
  • However, if an attacker manages to steal a users's session cookie, and there a two active sessions going under the same session ID (one by the legit user and one by the attacker), the timestamps/tokens will get out of whack and the server will invalidate the session so this timestamp/token layer protects the user if it gets that far. – espeed Jun 23 '11 at 22:15