Viewed   284 times

How do you prevent multiple clients from using the same session ID? I'm asking this because I want to add an extra layer of security to prevent session hijacking on my website. If a hacker somehow figures out another user's session ID and makes requests with that SID, how can I detect that there are different clients sharing a single SID on the server and then reject the hijack attempt?


I have accepted Gumbo's answer after careful consideration because I've come to the realization that what I'm asking for is impossible due to the restrictions of a stateless HTTP protocol. I forgot about what is perhaps the most fundamental principle of HTTP, and now that I think about this question seems a bit trivial.

Let me elaborate what I mean:

After User A logs in on, he is given some random session ID, for simplicity's sake, let it be 'abc123'. This session ID is stored as a cookie on the client side and is validated with a server-side session to ensure the user who logged in remains logged in as he moves from one webpage to another. This cookie of course would not need to exist if HTTP were not stateless. For that reason, if User B steals User A's SID, and creates a cookie on his computer with the value 'abc123', he would have successfully hijacked User A's session, but there is simply no way for the server to legitimately recognize that User B's request is any different from User A's requests, and therefore the server has no reason to reject any request. Even if we were to list the sessions that were already active on the server and try to see if someone is accessing a session that is already active, how can we determine that it is another user who is accessing the session illegitimately and not the same user who is already logged in with a session ID, but simply trying to make another request with it (ie navigate to a different webpage). We can't. Checking the user agent? Can be spoofed - but good as a Defense in Depth measure nevertheless. IP Address? Can change for legitimate reasons - but instead of not checking for the IP address at all, I suggest checking something like the first two octets of the IP, as even a user on a data plan network who constantly has a changing IP for perfectly legitimate reasons would only usually have the last two octets of their IP change.

In consclusion, it is the stateless HTTP that condemns us to never being able to fully protect our websites from session hijacking, but good practices (like the ones Gumbo has provided) will be good enough to prevent a good majority of session attacks. Trying to protect sessions from hijacking by denying multiple requests of the same SID is therefore simply ludicrous, and would defeat the whole purpose of sessions.



Unfortunately, there is no effective way to unmistakably identify a request that originates from an attacker in opposite to a genuine request. Because most properties that counter measures check like the IP address or user agent characteristics are either not reliable (IP address might change among multiple requests) or can be forged easily (e. g. User-Agent request header) and thus can yield unwanted false positives (i. e. genuine user switched IP address) or false negatives (i. e. attacker was able to successfully forge request with same User-Agent).

That’s why the best method to prevent session hijacking is to make sure an attacker cannot find out another user’s session ID. This means you should design your application and its session management that (1) an attacker cannot guess a valid session ID by using enough entropy, and (2) that there is no other way for an attacker to obtain a valid session ID by known attacks/vulerabilities like sniffing the network communication, Cross-Site Scripting, leakage through Referer, etc.

That said, you should:

  • use enough random input for generating the session ID (see session.entropy_file, session.entropy_length, and session.hash_function)
  • use HTTPS to protect the session ID during transmission
  • store the session ID in a cookie and not in the URL to avoid leakage though Referer (see session.use_only_cookies)
  • set the cookie with the HttpOnly and Secure attributes to forbid access via JavaScript (in case of XSS vulnerabilities) and to forbid transmission via insecure channel (see session.cookie_httponly and session.cookie_secure)

Besides that, you should also regenerate the session ID while invalidating the old one (see session_regenerate_id function) after certain session state changes (e. g. confirmation of authenticity after login or change of authorization/privileges) and you can additionally do this periodically to reduce the time span for a successful session hijacking attack.

Thursday, October 20, 2022

Your configuration is awesome. You definitely read up on how to lock down php sessions. However this line of code negates a lot of the protection provided by your php configuration: session_id(sha1(uniqid(microtime()));

This is a particularly awful method of generating a session id. Based on your configurations you are generating the session id from /dev/urandom which is a awesome entropy pool. This is going to be a lot more random than uniqid() which is already mostly a timestamp, adding another timestamp to this mix doesn't help at all. Remove this line of code, asap.

Checking the IP address is problematic, ip addresses change for legitimate reasons, such as if the user is behind a load balancer or TOR. The user agent check is pointless, it is like having a GET variable like ?is_hacker=False, if the attacker has the session id they probably have the user agent, and if they don't this value is really easy to brute force.

Thursday, September 1, 2022

After revisiting this topic several times, I have figured it out. There were two problems.

  1. session_regenerate_id() must be called before any HTML output is displayed and/or headers are sent. (It needs to be called as one of the first functions, just like session_start()).
  2. Order matters. session_name("TMU") needs to be called BEFORE session_start() to have the desired result - I didn't catch this before.

Basically what was happening to me was calling session_name("TMU") after session_start() was causing it to set TWO session ID cookies - two sessions - one named TMU the other just the default PHPSESSID. Changing the order fixed all my problems and regenerating the ID / destroying the old session works as expected now.

For anyone having problems doing this I suggest you echo out the $_SESSION and $_COOKIE arrays to see what is happening in your particular application.

Tuesday, October 18, 2022

It's hard to quantify in exact terms. First, remember that cookies are transferred between the client and the server in every single request. That's potentially many opportunities for someone to intercept them. Just assume that cookies will be intercepted at some point by somebody.

Storing the username, userid and (encrypted) password in the cookie:

  • leaks information which may or may not be useful or usable for nefarious purposes; i.e. for a successful login you need a username and a password, and you are waving both high up in the air shouting CAPTURE ME, the username even in plaintext
  • relies solely on the secrecy of your encryption algorithm for the password; if it becomes known, you have quite a security problem
    • since the encrypted password is known, an offline brute force attack can be mounted against it to reveal the encryption algorithm and plaintext password; this attack may or may not be purely theoretical, the fact that it exists at all should bother you
    • if it is possible at all to decrypt the password, you have already lost; the password is a secret only the user alone should know, not even you want to know at any point what the password is; if you do know the password, you have a giant responsibility to safeguard it, certainly you do not want to send it back and forth over HTTP the whole time; ? see password hashing
  • gives you no control over anything, all login information rests with the client (i.e. what do you do if you know any of the above was compromised?)
  • does not let you change passwords without invalidating all active logins

On the other hand, using only a meaningless session id:

  • reveals no useful information in the cookies
  • no opportunity to crack or brute force anything of value
  • server holds the ultimate power since sessions can be revoked at any time
  • it's simpler (simpler is always good in security)
  • using a full session with server-side state allows you to escalate privileges; e.g. require the user to have actively logged in with his password within the last x minutes from the current IP to allow him to change his password or email address ? provides security even if the session cookie should be hijacked

In short: session ids present no attack surface at all, since they're inherently meaningless. Userids, names and passwords present a very juicy target. Just from those basic points sessions should seem a lot more appealing. Assuming a perfect implementation with otherwise perfect security, both should be rather secure. However, you do not know what insecurities you have, you won't have perfect security. Assuming this, knowing this, the simpler system with fewer caveats should always be preferable.

Sunday, August 21, 2022

Any data the user keeps can be stolen; any data a visitor sends could be spoofed. Better to store the remote IP in $_SESSION when the session is opened, and compare the remote IP with every request. If they don't match, it's probably a hijack. Generate a new ID and have the user log back in.

Friday, November 25, 2022
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :