Dealing with POST data and expired sessions

Ok, so a client has discovered that when she leaves her add blog post page open long enough for the session to expire, and then tries to submit, she is logged out and her data lost. Needless to say, that’s not desired.

I have some ideas about how to solve this, but I wanted to run it by all of you before I start coding. First of all, I’d like to use cookies to keep the user logged in for 30 days unless they request a shorter session at login (for when they are logging in remotely, library or internet cafe, whatever).

Next, I’m thinking the best way to maintain that POST data is to throw it in the session. Because the session data is lost, I will probably need to store sessions in the database (more secure anyways, right?) and reload that session from a cookie value upon successful relogin. Can anyone think of a better way to handle this?

I’d like to try my hand at implementing this. I do have a question though.

If I’m securing a page using a user id stored in the session, I check for that user id fairly early in the whole process-- usually in the front controller before a specific page controller has been loaded. However, in order to to what you describe above, either each page controller would be responsible for securing itself (which would be a pain) or page controllers need a way to override the default action that occurs when a user isn’t logged in (displaying a login screen.)

So I guess my question is, how can the system you describe above be implemented without losing the ability to secure a whole section of the site at once?

We had the same problem with one of our clients and thought of (but did not implement so it’s not the tested) the following:

On a page of the website where the user can edit content like a blog entry you send an AJAX request to a very simple php script


session_start();

That should prolong the time of the session. I guess using session_regenerate_id() might cause trouble since the cookie than received by the AJAX request with the new session id might not be processed by the browser, thus effectively logging out because the user’s cookie’s rendered useless / outdated.
If you send such a call every minute or every two miniutes or something it causes almost no data traffic at all and your client should stay logged in :slight_smile:

That’s not always ideal (though probably better than our current setup). Sometimes you want the session logged out with a short period of inactivity. Using cookies will allow us to keep user data virtually as long as we want-- but it still doesn’t protect against lost POST data.

I have seen on other sites, if I post data and them am redirected to a login page because my session expired, once I log in it tells me it completed the action I was trying to complete before it redirected. I would hope that it is somehow saving the action to be completed until after I log in, and not just completing the action and then telling me to log back in (thus opening up the script to fake POST requests that can modify data).

I have never actually tried to implement this, but I think vBulletin handles this situation by somehow storing the submitted data, displaying the login form, logging the user in, then “resending” the submitted data again.

www-authentication solves all youor problems. If you don’t want to use it as the primary login mechanism, you can fall back to it when your session based login fails.

What if the login page receives the posted data (POST) and the URL it came from, and the login page leads her back to where she was with the data she submitted after successful login?

What you COULD do is make a javascript that requests a blank page with AJAX which has got session_start() on it, have the javascript execute the AJAX every 60 seconds and in theory this would result in the session never expiring :wink:

In that case, simply setting session.gc_maxlifetime to a higher value is probably a better solution.

Why not always ask for a username / password on a form?

If the user session is valid then it is optional. If it expires whilst the user has the form open, then treat like a validation error, and redisplay the form.

First of all, I’d like to use cookies to keep the user logged in for 30 days unless they request a shorter session at login (for when they are logging in remotely, library or internet cafe, whatever).

Uh, doesn’t 30 days seem a little long? What’s wrong with 24 hours? How many people will miss that they can request a shorter session? Should we trust the user to set more security, or is it better to set more security and let the user remove it (for their own harm, done by their own hand)?

For those suggesting AJAX, what would be the solution for users with mobiles and other devices likely to have JS off? (kyberfabrikken’s solutions?)

Often when I’m told to go log in again, I’ll hit my back button, copy-pasta what I wrote, then go back forward and try logging in (this works because the POST didn’t happen and instead I get a different URL sent to me, so my info isn’t lost, but is still in my browser cache). Sometimes logging back in doesn’t work due to server loads (was very common on a forum I am on), so I can always paste what I wrote in a text editor just-in-case.

What you need to do is this:

#1 make sure all your forms post to them-selfs (302 to them-selfs on success, so you don’t have the “refresh” confirmation popup)

#2 - In case you have an “if (is not logged in) { redirect to login page; }” block in more than one place, put that in a function and call that function everywhere.

#3 - In that function, before the actual redirect, check 2 things:
a) If the request was GET, and if so, store the URL in a session variable (redirect to it after login)
b) If the request was a POST, store the #1 the URL and #2 the posted data in the session. Redirect to that #1 URL after the login, and use the #2 data to pre-populate the form fields on the page.
(Make sure to tie the data to the logged in user id or something)

So, from the user’s point of view:

  • login
  • go to edit profile
  • fill in profile
  • chase bag in the wind for 45 min (session is 15)
  • come back, submit the edit profile page
    — get a “login here” page.
  • login
    — get redirected to the submitted page, pre-populated with all the posted data, and some kind of message saying to repost, since the data was not saved cause of session time out.

Hope that helps.

A 12 hour session expiry works for a workday. They basically have to re-login the next day. If you leave the form overnight, do you really need to still be able to submit it?

I haven’t implemented the solution to this myself, but we’ve using a ping to renew the session cookie. We’ve also used a count down timer to warn the user that they should submit soon, or at least go through a preview cycle to renew their session.

Cool I will look into that.

That would have to be done with sessions, and was my initial thought. It seems like it should fit in well with a post-redirect-get mechanism.

Interesting thought. My guess is it would be confusing to most users, though. (“Why do I have to log in every time I edit a page?”)

Didn’t really have a specific reason for 30 days, just wanted something longer that clients don’t have to think about.

Interesting thought indeed. I’ve had this problems with users that were writing something along the length of the bible in a textarea, and they were surprised when they found out that they were logged out in the meantime and naturally, that had upset them as they now lost the text they wrote. When I explain it’s a security precaution, they will usually calm down, but I really feel bad for the users: there has to be a way around it.

I do agree with allspiritseve though: always asking them for their username and password will confuse the users of my applications, and very understandable too, I think I’d be confused just as well as my end-users. I mean, while writing this reply, I wouldn’t expect that I’d have to pass along my username and password, as it already says: “Logged in as webaddictz”.

I do, however, think there is a middle ground? When the form is submitted, check if there is a session, if there is not, save the information somewhere and redirect the user to a login page. After login, send them back to the form and let them submit again. No Ajax involved, and it will work on every browser.

You could, of course, create an Ajax variant too. Upon submittal of the form, do an Ajax call to see if the session is still alive. If not, ask the user to fill out username and password, and submit that with form. On the serverside, log the user in and save the form’s value(s). That actually sounds like a nice idea.

Yes, I liked that suggestion too. I think you’re over complicating it though.

What about you just show the form as usual. When the user submits it; if the session has expired you redisplay the form with the user + pass fields added to it (And the rest of the fields filled in from post data). That way, the normal flow would work unchanged, and you only do something different if the users session has expired. Basically, you treat the expired session as a validation error on the form, which is actually quite intuitive (IMHO).

If you wanted, you could even redisplay the page with the original content in hidden fields, and only the new user + pass fields displayed. This gives an illusion about being redirected to a login page, when - in fact - there is no redirection going on. Since there is no actual redirect, you don’t need to temporarily store the form contents in session or elsewhere.

Well, over-complicating is easier than keeping things simple, unfortunately. I guess you’re right :wink:

That actually sounds like a better, less cluttered way of achieving the same. The user would probably be a lot happier with this. It does make sense: the fact that a user’s session is expired is just another possible validation error. I can see one potential pitfall though: when a non logged-in user is not allowed to view any entries, let alone edit them, where will you validate whether or not you should actually display the page, seeing that an expired session essentially equals a user that is not logged in.

Or is this something we shouldn’t be afraid of? The only way the user + pass form entries will be shown is upon a POST, so a non-logged in user would have to guess the correct URL and submit a POST request which includes the values that are to be written and so he doesn’t have the ability to override if he’s not allowed to and can’t read it because the GET would give an error.

Gosh, you’re right. I am over-complicating. This is a viable, secure and very user-friendly option and I’ll be writing this in my newest applications from here-on now.

By keeping the state at the client, and not the server, things do become less complicated, this is a very nice example of that. No Javascript magic, no complicating stuff like temporarily storing values, just another POST. Sounds darn good to me.

You would use the POST data from the request to populate the form, so I don’t see any security problem there.

That’s what I said: I am over-complicating. The solution is secure, viable and most user-friendly. Allspiritseve, I think you have your answer here.

Hi :slight_smile:

I use a similar approach, only I open a modal with login and pwd. If credentials are accepted, the form is submitted. After three errors, the content is saved into a db (as a draft, for a later use), and the user redirected to the usual login page.

:slight_smile: