0

I'm building a PHP based web app and have implemented a session variable based login method. Before anything is loaded, this method clears the "logged in" state of all those that have spent X amount of time on the site without loading a new page or reloading the same page. Now this is working great, however this only does the check when the page is loaded and doesn't look for mouse / keyboard activity (think about a long form being filled out).

A similar question has been asked here however the code's security vulnerability was never questioned. I also found Paul Irish's solution to this however didn't find any reference to security there either.

Is it a realistic fear at all that the javascript code may be de-activated / intercepted in case I'd keep an "absolute timeout" server side? How do other big web app designers do it?

Community
  • 1
  • 1
benomatis
  • 5,536
  • 7
  • 36
  • 59
  • 4
    Why don't you just restrict the session's lifetime server-side? No need to have any JS on the client that way. – thejh Jun 10 '13 at 09:06
  • Just store the session start time in the session, if it does not already exist. What are you actually trying to achieve? Do you want people to spend no more than X minutes per page? – halfer Jun 10 '13 at 09:51
  • @thejh: wouldn't that still need a page load to work? what if the user doesn't load the page at all but just types on it? – benomatis Jun 10 '13 at 09:57
  • @webeno: Well, he can't send evil commands to your server anymore. All he can do is view the information that's already in RAM, and there's no safe way for you to force secrets out of the RAM anyway. – thejh Jun 10 '13 at 09:59
  • @halfer: if i store the start time in the session, isn't that something that can be hacked / altered? I'm trying to ensure the app is really only used by "real" users of the app and if they forget to logout, that I do it for them, ensuring maximum security. Or is this a misconception? Yes, I don't want them to remain more than X minutes *idle* (not doing anything, not clicking, not typing). Is it not a realistic security threat to leave them logged in indefinitely? – benomatis Jun 10 '13 at 10:01
  • @thejh: as you can see in the description, I already do the server-side idle state check, what I'm looking for really is to see if adding the client-side check, would I really add security or rather take away? I'm just wondering why some of the biggies do use such a system and everywhere I read it's either not specified or said to be not secure... by the way, how does Goole and facebook do it...? – benomatis Jun 10 '13 at 10:07
  • 1
    If you set the start time on the server side session then no, it cannot be hacked. For every page load, check if this time is older than your maximum session time, and if it is, log the user out. Forget about the JavaScript thing, that can be turned off. – halfer Jun 10 '13 at 10:24
  • @halfer: The timeout amount is defined as a constant and `time()` plus that constant is added to the DB to the user along with a meaningless token (the only thing) set in the session variable, so I think I'm fine with the server-side checking. I know javascript can be turned off, but if it is, the user would be logged out at page load, otherwise it could be an added value of security (but is it?). The point of my question is really around security, not only practicality. – benomatis Jun 10 '13 at 11:57
  • If JavaScript is turned off, then the session won't die until the user requests another page (so in theory the session will still be "live" but to no practical effect). As soon as they request **anything** if the constant time has passed, you can log them out at that point, and there's nothing that can be done to bypass that (except the user keeping the session artificially alive by requesting pages pointlessly, but then of course that **should** keep the session alive, since you can't tell why they have requested a page). – halfer Jun 10 '13 at 12:06
  • @halfer: can I safely say then that, as I'm already allowing users to extend their session with a page load, it isn't any less secure to allow the same with mouse moves or keystrokes? I guess I just have to make sure that the client side script is nothing more than a count-down timer, and that meaningless token that I talked about (only meaningful on the server side), plus maybe another check that tells the server if the js script was invoked at all... correct? – benomatis Jun 10 '13 at 14:36
  • _Can I say that ... it isn't any less secure to allow the same with mouse moves or keystrokes?_ Correct. I don't know that you need the meaningless token though: that's the job of the cookie. – halfer Jun 10 '13 at 15:26
  • 1
    @halfer: with "meaningless token" I just mean I don't plan to store the password hash for example... Thanks for your help, you may want to provide this as an answer and I'm happy to accept it as the correct one. – benomatis Jun 10 '13 at 16:56

1 Answers1

2

There's a number of inter-related issues here. My approach is that this can be done entirely server-side first, and then a JavaScript improvement added atop such that it doesn't matter if the client-side stuff fails to run.

The core of the solution is to set a last_seen time on the server when the user logs on. Whenever you detect any user activity (either a page rendering or an AJAX response), check whether this time is within acceptable bounds for you, and if it is overwrite it with the current time. If it is outside of the current bounds, destroy the session on the server side, and force a redirect to the login page, with a suitable message.

Once you have done that, there is no way that server-side value can be tinkered with, unless the user artificially refreshes their page pointlessly in order to avoid the timeout - but in that case, you would be unable to determine the difference between a "real" page request and one designed just to reset the session timer. If you are worried about malicious software on the user's computer, or an advanced man-in-the-middle attack on the user's connection, then you've got bigger problems than session timeout anyway.

Once this is set up, you may wish to use JavaScript to run a timer on each page that automatically shows the logged-off-automatically message. Just set this timer for the same length of time as your timeout, and of course restart it if an AJAX operation is triggered on the page. You could inject this message into the DOM, rather than redirecting, so if the user is filling out a form, they don't lose their work.

As you say, you could always detect form key-strokes to reset the timer. To do so, send an AJAX operation to the server that answers with an empty reply - that will send the cookie automatically - just ensure that your standard session code is run here too. Do use a JavaScript timer so that you don't send an AJAX op for every press - if it sometimes goes ten seconds later than the key press, then you'll not overwhelm the connection and you'll ensure your application remains speedy.

halfer
  • 19,824
  • 17
  • 99
  • 186
  • just a quick question: do you have a practical implementation of the last paragraph? I mean, how do I send that AJAX op to the server without refreshing the page and without making javascript to directly communicate with the db? I thought about using javascript to create/update a second cookie or session variable that would be checked server side when the user actually loaded a different page. what do you think? – benomatis Jun 11 '13 at 21:04
  • AJAX ops by definition do not involve a page redirect, and no JavaScript communicates with the database directly. What happens is you make an AJAX call to a PHP script, which then updates the server session on behalf of the client. I'd suggest writing this yourself; in the first cut, just use something like jQuery, binding on `input` elements with events such as `keypress` or `change`. [Here's an example](http://api.jquery.com/keypress/) of triggering from an event. Once that works, you can do the rate limiting stuff, which is a bit more complicated. – halfer Jun 11 '13 at 22:10
  • So basically i'd update the input element's value using jQuery and call that value server side when the page is loaded (I realized I wouldn't need a session variable or cookie for this, I could just call it using the POST method...) or call a server side session stop (log out) if there is no activity, correct? What do you mean by "rate limiting stuff"? – benomatis Jun 12 '13 at 05:46
  • No, not updating the element's value - attaching an event handler to it, so that when it changes, it starts an AJAX op to reset the session time on the server. The rate limiting was in my last para - you don't want to start an operation for every key press, since if you've recently sent one, you know the session does not need resetting. Send one only if you've not already sent one in the current page for two minutes, possibly. – halfer Jun 12 '13 at 08:47
  • Well, this would only take care of filling out forms, but would ignore clicks in a javascript picture viewer for example. On the other hand, I'm storing the login time in the db and the timeout as a PHP constant, the session variable I'm using is only a token used to identify the user logged in (this token is also stored in the DB next to the user). So in order I can prolong the session, I would have to connect to the DB client-side (a big no-no) or just update a variable that the server would look for at the next page load. By the way, are you talking about AJAX partial page updates? – benomatis Jun 12 '13 at 09:22
  • For the JavaScript viewer, you can add additional (click) event handlers that do the same thing. Yes, if you wish to prolong the session, you will have to reset something on the server side. Either reset `$_SESSION` or maybe write something in your database (I can't be sure without knowing your architecture, and this all needs designing anyway). No, not partial page updates - the server can just reply with a JSON string to say everything was okay. It sounds like it might be a good idea to plan this out on paper, and perhaps give it a go? – halfer Jun 12 '13 at 09:49
  • I think I'm missing the practical knowledge of how I would build it your way using AJAX and the JSON reply, so I'll have to try and do it my way, and see if it works, I might be posting it on codereview... – benomatis Jun 12 '13 at 15:58