#1
  1. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2002
    Location
    Queensland, Australia
    Posts
    827
    Rep Power
    141

    Regenerating session IDs safely with concurrent request?


    I had been regenerating sessions IDs on the roll of dice to prevent session fixation. One of the pages on my site triggers enough AJAX requests to pretty much guarantee the session ID will be regenerated when the page loads

    The problem is that the AJAX requests are concurrent and some send with the expired session ID because the new one had not yet been recieved, causing the entire session data to be lost.

    I have two possible solutions to this in mind:

    a) Don't regenerate the ID on ajax request
    This would be reasonably safe as the ajax requests are just for pulling non-sensitive data and don't perform any other sensitive operations.

    b) Don't destroy the previous session
    Before regenerating the session ID, I would put a flag in the session indicating that it has been expired and should be destroyed after a short period (i.e. 1 minute), then regenerate the ID without destroying the old one. So the old session ID would continue to be valid for 60 seconds after it had been regenerated. Requests after this time would cause the session to be destroyed.

    I should mention that I've written a session class very similar to Zend. I've taken a look and Zend and it doesn't seem to have any mechanism in its class to solve this issue. So I wonder if I'm missing something.
    Ooh, they have the Internet on computers now!
  2. #2
  3. Mad Scientist
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2007
    Location
    North Yorkshire, UK
    Posts
    3,660
    Rep Power
    4123
    I've come across this issue before - when I was using session_regenerate_id on every request

    I take the first method of only regenerating the session id on full page loads; at the same time I regenerate my anti XSRF tokens as well

    I've tried to look at other methods like having two sessions - (imagine manually recreating the functionality of session start) with a time-delay cross over where the two sessions held references to the other's ID; all session data was databased and not destroyed immediately...but when I last tried this I couldn't get it to work.

    I also looked at pairing up session id with Ip address; but I'm told this can be forged too

    the key is getting the user/client to send something that is unique to them, but you never told them about it (like a time-varying hash or encryption of their password - which you can validate server side)
    I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

    PDO vs mysql_* functions: Find a Migration Guide Here

    [ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]
  4. #3
  5. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2002
    Location
    Queensland, Australia
    Posts
    827
    Rep Power
    141
    I ended up using a combination of a) and b).

    With normal page loads, the session is regenerated and the previous session destroyed. I like the safety of this.

    With the pages delivered through AJAX, I regenerate the session ID without destroying the previous one. I basically flag the previous one as a zombie which is automatically destroyed if requested 1 minute after zombification.

    I may drop the work I've done on b). It required quite a bit of effort to get to work and I'm not sure it's necessary. It will mean that session fixation exists on the AJAX content, but so long as the AJAX does not perform sensitive operations, I don't think it can be exploited to any great success. Users will still be accessing normal pages which will frequently invalidate a hijacked session ID.

    I'm still curious how this is typically managed with Zend framework.
    Ooh, they have the Internet on computers now!
  6. #4
  7. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,301
    Rep Power
    7170
    Before regenerating the session ID, I would put a flag in the session indicating that it has been expired and should be destroyed after a short period (i.e. 1 minute), then regenerate the ID without destroying the old one. So the old session ID would continue to be valid for 60 seconds after it had been regenerated. Requests after this time would cause the session to be destroyed.
    This sounds like a race condition waiting to happen. Your old session would need to be marked as read-only at the point where the new one is created, otherwise any data written to it will be lost. Trying to write the new session ID into the old session data would open up a second race condition too.

    I'm still curious how this is typically managed with Zend framework.
    The simple answer is that it's not, for two reasons:
    1) Most web sites don't run concurrent AJAX requests.
    2) Most web sites don't regenerate the session ID frequently.

    I had been regenerating sessions IDs on the roll of dice to prevent session fixation
    Regenerating the session ID on every page request does not prevent session fixation, although it does somewhat mitigate the risk by requiring the attacker to act immediately (of course, if the attacker is an automated piece of code that isn't exactly difficult).

    When you regenerate the session ID you still send it back as a cookie in the HTTP response. This means that anything monitoring the network communication can still intercept that session ID, and any JavaScript running on the page can still read the cookie and get the session ID. All the attacker needs to do is issue a request back to your server using that ID before the legitimate owner of the ID does so, and your server will then give the attacker the next regenerated session ID and the legitimate user will get logged out when they load their next page because they have an invalid session ID. Assuming that most users probably spend at least a few seconds reading a page, this still gives the attacker a lot of time to do malicious things if their attack is automated.

    Even the fact that you're running frequent AJAX requests won't prevent this. A session fixation attack is usually implemented using an XSS vulnerability, and an XSS vulnerability can just as easily be used to abort your AJAX requests as it can steal the cookie data.

    The best way to protect against session fixation is to prevent the ID from being stolen in the first place. This means protecting against XSS and using HTTPS.
    PHP FAQ

    Originally Posted by Spad
    Ah USB, the only rectangular connector where you have to make 3 attempts before you get it the right way around
  8. #5
  9. Mad Scientist
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2007
    Location
    North Yorkshire, UK
    Posts
    3,660
    Rep Power
    4123
    so i'm pretty well protected against XSS, but the way in which ssl certificates are dealt with confuses me time and time again

    What's the cheapest way to certify the SSL layer that does not produce browser warnings?
    I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

    PDO vs mysql_* functions: Find a Migration Guide Here

    [ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]
  10. #6
  11. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2002
    Location
    Queensland, Australia
    Posts
    827
    Rep Power
    141
    Originally Posted by E-Oreo
    Trying to write the new session ID into the old session data would open up a second race condition too.
    Technically, I don't do that. I turn the session into a Zombie, regenerated ID, then unzombie the session. The old session ID remains with it's previous data. And it's flagged read-only so a process can't accidentally bring it back to life. It works.

    Regenerating the session ID on every page request does not prevent session fixation.
    *groan* Here we go. It helps, and to suggest otherwise is irresponsible advise for those who don't know better.

    This means that anything monitoring the network communication can still intercept that session ID
    TRUE. But, again, it helps reduce the risk.
    any JavaScript running on the page can still read the cookie and get the session ID.
    Only if you neglect to set them to HTTP Only and your visitor is using a very old browser. And then if they are using an old browser, regenerating the ID helps to reduces the risk.

    Even the fact that you're running frequent AJAX requests won't prevent this. A session fixation attack is usually implemented using an XSS vulnerability, and an XSS vulnerability can just as easily be used to abort your AJAX requests as it can steal the cookie data.
    Believe it or not, my AJAX requests aren't designed to prevent session fixation, they are designed to request data. The regeneration of session IDs was a side effect since AJAX requests and normal requests were treated the same. Woop-dee-doo if XSS is used to stop it. And, again, by regenerating the ID, you are reducing the risk.

    The best way to protect against session fixation is to prevent the ID from being stolen in the first place. This means protecting against XSS and using HTTPS.
    No! Stopping XSS is something you can only attempt, unless you fork out for very expensive auditing software. Any good programmer know he or she is not a flawless programmer and does not arrogantly believe they never make mistakes that would compromise security.

    I'm quite concerned by E-Oreo bold advise in this thread. So let me clarify for those who might not know better:
    1. You do regenerate session IDs, and you do it frequently. How frequently is debatable, but you don't leave it to chance.
    2. You always regenerate a session ID after performing a secure event (i.e. login, logout, password change, any change of access rights)
    3. You always mark session cookies as HTTP only. Preferably, make all cookies as HTTP only unless you need JS to access it.
    4. Try your best to write code not vulnerable to XSS and back it up with frequent audits.
    5. Use HTTPS if you can. But this is not always up to the developer, and good developers will ensure the software is as secure as possible in the absense of HTTPS.

    Everyone makes mistakes and that's why don't ignore anything when it comes to security.
    Last edited by DrWorm; July 20th, 2012 at 04:20 AM.
    Ooh, they have the Internet on computers now!
  12. #7
  13. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,301
    Rep Power
    7170
    What's the cheapest way to certify the SSL layer that does not produce browser warnings?
    Basically just shop around until you find a cheap one. Encryption-wise the certificates all offer the same protection. The provider usually advertises the percentage of browsers that their certificates are compatible with, which should be something like 99.X%. There is a huge variety of pricing, but I think you can find them for as low as $15-$30 per year.

    Originally Posted by DrWorm
    *groan* Here we go. It helps, and to suggest otherwise is irresponsible advise for those who don't know better.
    Right. That sentence of mine that you quoted does not end in a period. The part you omitted states very clearly that it does help:
    Originally Posted by E-Oreo
    Regenerating the session ID on every page request does not prevent session fixation, although it does somewhat mitigate the risk by requiring the attacker to act immediately (of course, if the attacker is an automated piece of code that isn't exactly difficult).
    Believe it or not, my AJAX requests aren't designed to prevent session fixation, they are designed to request data.
    That's not actually what I meant to suggest. What I was getting at is that your AJAX requests do actually make session fixation harder, but not to the point where it is worthwhile to implement AJAX requests for that sole purpose. I understand that your AJAX requests are not implemented solely or even partially for that purpose.

    Stopping XSS is something you can only attempt, unless you fork out for very expensive auditing software
    Actually there is a variety of free software for detecting XSS and other vulnerabilities that works pretty well. The one I can think of off the top of my head is Netsparker Community, but I'm sure there are several others too.
    Last edited by E-Oreo; July 20th, 2012 at 08:59 AM.
    PHP FAQ

    Originally Posted by Spad
    Ah USB, the only rectangular connector where you have to make 3 attempts before you get it the right way around
  14. #8
  15. Mad Scientist
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2007
    Location
    North Yorkshire, UK
    Posts
    3,660
    Rep Power
    4123
    maybe I'm being grossly naive, but isn't XSS easily avoided by just not outputting user-supplied data?

    And if you do have a requirement to output it (eg CMS or other web app) it's run through htmlentities (assuming html output)
    I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

    PDO vs mysql_* functions: Find a Migration Guide Here

    [ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]
  16. #9
  17. Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Aug 2002
    Location
    Queensland, Australia
    Posts
    827
    Rep Power
    141
    Originally Posted by Northie
    maybe I'm being grossly naive, but isn't XSS easily avoided by just not outputting user-supplied data?

    And if you do have a requirement to output it (eg CMS or other web app) it's run through htmlentities (assuming html output)
    Yes, which is a simple thing to guarantee if the extent of your sytem is a contact form. For larger system, it only takes one variable to be neglected to make the system vulnerable.

    In the same way, if you still use the old PHP MySQL library, you must consistently use mysql_real_escape_string() to protect your queries from SQL injection. Forget it once and your vulnerable to SQL injection. Which is why prepared statements (offered with PDO and MySQLi) are preferred.

    Originally Posted by E-Oreo
    Right. That sentence of mine that you quoted does not end in a period. The part you omitted states very clearly that it does help:
    My apologies. I had a frustrating day at work. Although I'm not clear on the point of your post. If you appreciate that session IDs should be regenerated, then why start up a conversation about how sessions work and how ineffective it is to regenerate IDs? If your point was to suggest that regenerating IDs is overkill on AJAX requests, it was lost amongst the advise to simply not write XSS vulnerable code, and always use HTTPS.
    Ooh, they have the Internet on computers now!
  18. #10
  19. No Profile Picture
    Lost in code
    Devshed Supreme Being (6500+ posts)

    Join Date
    Dec 2004
    Posts
    8,301
    Rep Power
    7170
    maybe I'm being grossly naive, but isn't XSS easily avoided by just not outputting user-supplied data?
    Not outputting user-supplied data does prevent XSS, but I wouldn't classify that as easily avoided because virtually all systems output user-supplied data at some point. User-supplied data doesn't just mean data coming from $_POST or $_GET; it would include data from all external sources, including your database.

    Although I'm not clear on the point of your post. If you appreciate that session IDs should be regenerated, then why start up a conversation about how sessions work and how ineffective it is to regenerate IDs? If your point was to suggest that regenerating IDs is overkill on AJAX requests, it was lost amongst the advise to simply not write XSS vulnerable code, and always use HTTPS.
    My post wasn't really targeted at you, but at the couple hundred googlers who will probably wonder by this thread in the next couple years.

    The main point was that frequently regenerating IDs by itself is not sufficient to completely prevent session fixation. I suspect now that you probably knew that already, but (a) that's a relatively common misconception, and (b) someone who didn't already know that and read the first sentence of this thread might get that impression. I went on to explain exactly why it's not sufficient, which is why the post ended up being so long.
    PHP FAQ

    Originally Posted by Spad
    Ah USB, the only rectangular connector where you have to make 3 attempts before you get it the right way around

IMN logo majestic logo threadwatch logo seochat tools logo