7

I have developed this PHP web application which is now running for some months. Suddenly one of the users complained that he was able to login, but the session was terminated as soon as he clicked on any button! The same problem happened on different browsers.

After some tests I realized that a brand new session ID was created every time the user clicked on any button, probably because the original session was expired.

For whatever reason I took a glance at the user's computer clock and... surprise! His clock was 3 months in the future! I didn't know if such thing could have any relation to the failure, but I did fix the clock. Still it didn't work. I erased all cookies. Still nothing. So I restarted the browser - and then it started working again!

The closest information I got about this issue was Shimon Amit's answer to this question. Good, now I know that the clock "misconfiguration" is the cause. The problem is... I cannot keep every customer's computer clock under control. Some of them may have their computer clocks set in the future.

My question: is there any solution for this? Any trick? I don't want customers to face such errors as they may find it "lame" and break their trust on the application, even though it's not really my fault (in a sense).

Community
  • 1
  • 1
Bizarro
  • 399
  • 4
  • 12
  • 7
    I don't think it's unreasonable to expect that a user's clock is relatively accurate. maybe not down to the second, but 3 months is rather ludicrous. Not as nuts as being 20 years in the past, though. – Marc B Oct 31 '12 at 15:29
  • I absolutely agree. Unfortunately the users will blame ME if the application stops working and eventually I will have to waste time analyzing the failure - if it happens in the far future, I may have forgotten this "bug" and will spend days trying to figure it out. So I'm not actually looking for a real solution, but just trying to make the application stupid-proof. – Bizarro Oct 31 '12 at 15:56

5 Answers5

5

Session cookies (like all cookies) are controlled and deleted when expired by the client browser. Even if you set a far out expire date (which you might not want to do anyhow) all the client needs to do is move his clock even farther forward and it will expire.

Ray
  • 40,256
  • 21
  • 101
  • 138
2

You can extend your session timeout to a later date. Perhaps you can use cookies that don't expire (sessions are related to cookies on the client side) Otherwise, your client's browser is just doing what it's designed to do.

EDIT: Javascript Option

This is a total hack, but you COULD use javascript to get the current time on the client machine and send it back to the server, then adjust the timeout on your session cookie to expire three months after that. See http://www.w3schools.com/jsref/jsref_gettime.asp

Once you have retrieved the client time, you can reset the session expiration using session_cache_expire(). http://www.php.net/manual/en/function.session-cache-expire.php

EDIT: 100% Server Side Option

Another option that I thought of would be to set a session cookie with no expiration, but track the time the cookie was set on the server, say in a MySQL table. You would also need to keep track of the last activity. Whenever a logged in user makes a request, you could check the start time of their session and their last activity. If the current time is greater than your acceptable timeout for either of these, then destroy the session server side and bring them back to the log in page. If the session is still ok, then update the last activity associated with that user so you can compare on the next request. No client side code necessary.

Joshua Kaiser
  • 1,461
  • 9
  • 17
  • OK... so I will make the same question as I made to Sammitch: is there a way to capture the browser's date without javascript? – Bizarro Oct 31 '12 at 16:02
  • I'm not aware of a non-javascript solution. I've done some searching on the web in the past half hour and haven't been able to find anything. I think you might be able to use a non-expiring cookie and handle it server side though. I'll edit my answer and explain. – Joshua Kaiser Oct 31 '12 at 16:55
  • @Bizarro I've edited my answer to add a full server side solution to your problem. Thanks! This one made me think! :) – Joshua Kaiser Oct 31 '12 at 17:06
  • Please look at my answer to Sammitch. The solution with $_SERVER['REQUEST_TIME'] looks fine. I just have to test it on the production server. – Bizarro Oct 31 '12 at 17:11
  • I'm thinking... in order to get rid of any MySQL activity, do you see any problem setting the last activity timestamp on the session itself? So everytime the page is reloaded, I will compare, say, $_SESSION['last_activity_datetime'] with the current server time - if the difference is bigger than 30 minutes, destroy the session. Otherwise, update $_SESSION['last_activity_datetime'] and allow access. All this logic could be encapsulated on my validate_session() function. What do you think? – Bizarro Nov 01 '12 at 16:56
  • That seems to make sense, just so long as your session isn't expiring earlier than you expect it to. – Joshua Kaiser Nov 01 '12 at 17:51
2

I fully agree with @MarcB's comment that you can't assume responsibility for how grossly misconfigured a user's machine could be. If you really want to make a difference in this regard I would suggest using PHP to output a small snippet of javascript that includes the time on the server. The snippet would compare that time to the time on the client computer and raise an alert if the time differs by more than X from the server. [say, 24hours or so]

Sammitch
  • 30,782
  • 7
  • 50
  • 77
  • I like that...the only point is: I'm trying to develop the application in a way that it works with or without javascript. Would there be a way to do the same check on the server side, maybe getting the browser's date? Is it possible at all? – Bizarro Oct 31 '12 at 15:50
  • As far as I am aware browsers do not send timestamps with HTTP requests, so the only way to determine the time set on the client PC would be with some form of client-side code, ie: JavaScript. Seriously though, I would not even bother with this. If the client's clock is out by more than 5min/2hours/24hours they will have increasing amounts of problems with a lot more than just one website. – Sammitch Oct 31 '12 at 16:15
  • I did some research and found the $_SERVER['REQUEST_TIME'] variable. It seems to work properly, so I will embed a date comparison between $_SERVER['REQUEST_TIME'] and the server time. If the difference is bigger than 30 minutes, the user won't be able to login. Yes, I will be that radical :-) – Bizarro Oct 31 '12 at 17:08
  • @Bizarro, I don't believe that time has anything to do with the client. If I understand correctly, it's the time that the server received the request. You shouldn't ever have a difference higher than a few seconds. – Joshua Kaiser Oct 31 '12 at 17:13
  • @JoshuaKaiser Oh... yes, it looks like... Too bad. So probably I will have to be in javascript's hands :-o – Bizarro Oct 31 '12 at 17:30
  • @Bizarro, no you won't. Please see my 100% Server Side Option. – Joshua Kaiser Oct 31 '12 at 19:07
1

Any trick?

Use session cookies. Not session in the meaning of PHP sessions, but browser session. Session cookies are stored until the user closes the browser. They are immune to whichever clock the user has set her computer. They will last until the browser is closed.

That is normally appropriate for PHP-session related cookies.

For PHP you need to ensure that the session cookie parameter lifetime is configured to 0 before the session starts. That is either the ini setting session.cookie_lifetime or by calling the session_set_cookie_params function.

For a more detailed description of cookie parameters, see the documentation of the setcookie function.

Second part of the trick is that you place a session start timestamp and a last activity timestamp into the PHP $_SESSION. Those are server based so have always the same base.

Check them, e.g. if the session is too old, last activity too long ago etc., destroy the session and force the user to login again.

You could even use that second part of the trick to combine it with a cookie that has it's expiry 10 years in the future (okay, browser might not like that, maybe you just want your three months).

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • I must confess that my session knowledge is quite poor. I would have to study your post carefully, but I already can say that this solution looks more "clean" (or "correct") than my own approach. The only personal drawback is that I would have to rewrite parts of my application - that would be time-consuming. – Bizarro Oct 31 '12 at 17:20
  • Well the first part is actually PHP configuration (and 0 the default value). The second part is additional, however is generally good that sessions don't last eternally, so tracking these times allows to do more stuff, not only solving the problem in your question but also to close sessions after some time of inactivity or general session time so users are required to login again for security reasons. – hakre Nov 01 '12 at 02:05
-1

Try to disable the session timeout or at least set it far into the future. That should do the trick.

Louis Huppenbauer
  • 3,719
  • 1
  • 18
  • 24