How does play validate a cookie?
I noticed that after I restarted the server I was still logged in even though I
don't presist any session data in the database.
I also noticed
that I could set the date on the server to be larger that the exipry
date of the cookie and still I was logged in.
I logged out
(saved the cookie to a text file) and the browser lost the cookie. Then I
recreated the cookie from the text file and I was logged in again.
The cookie looks like this:
PLAY_SESSION=e6443c88da7xxxxxxxxxxxxxxxxxxxxxxxxxxxxx-userid%3A1
// My logout code
def logout() = Action {
Ok("").withNewSession
}
From the documentation
Discarding the whole session
There is special operation that discards the whole session:
Ok("Bye").withNewSession
You didn't specify how do you authenticate users, so I just guess, that you;re using simple sample which is... simple.
It uses user's id to identify the user, and check if signed session cookie wasn't manipulated, therefore if you'll recreate the cookie with proper signature it will be valid still.
You should create some area for session's keys on the server side ie. in DB or in memory cache (Which will be faster than DB). Its key should be randomly generated (and preferebly quite long) for each successful login action, and should also contain data for identifying user, expiration date etc. Next you should put this random sess_key to the Play's session instead email address of logged user or id of his row in DB, and after logout and/or expiration date it should be removed. In such case even if you'll loose the cookie after logout it will be impossible to login properly with non-esixting sess_key.
AFAIR standard memory cache will be purged at every restart of the application, to make sure that all sess_keys from DB will be removed as well you can use Global object and truncate the table in onStart(...) method.
I found the answer reading the documentation more carefully and combining different parts.
There is no technical timeout for the Session. It expires when the
user closes the web browser. If you need a functional timeout for a
specific application, just store a timestamp into the user Session and
use it however your application needs (e.g. for a maximum session
duration, maximum inactivity duration, etc.).
It’s important to understand that Session and Flash data are not
stored by the server but are added to each subsequent HTTP request,
using the cookie mechanism. This means that the data size is very
limited (up to 4 KB) and that you can only store string values.
So that was what i feared that if the cookie get lost anyone can log in to the server for all future.
What I have to do to secure this is to add a self-made timestamp authorization (save a timestamp in the cookie and validate sever side)
Related
Scenario:
User logs into website.com using firefox. Login credentials are valid, user is directed to member's page.
User tries to log in to website.com using chrome. Login credentials are valid, because use is already logged in using firefox, system will throw error, asks user to close other session to login through chrome.
How can I detect that? Right now I am able to detect it if user only use one browser, but seems to break when user uses two different browsers to log in at different times.
EDIT* I want to say it's more than just using different browsers, the website should not allow multiple people to log in with the same login credentials.
I am assuming your application is j2EE/servlet based. If it is the case, two browsers are independent of each other, hence they have their own sessionId and can function independently, as long as your application does not interfere.
To prevent this scenario, one way to implement is, keep a hashmap of SessionID and UserID in your servlet. You populate this on every successful login, for example via a filter or a valve. When you are populating the hashmap, make a check, to see if any other sessionID is already using this userID. If it is used, check if the corresponding sessionID is still active. If it is not active, allow the login, and delete the stale sessionID. If it is active, terminate the other session and allow the login.
If you're using Spring Security - it may be specified by parameter in the configuration file.
If just plain java - during log-in put user's session id to some storage; when he tries to log-in again you should prohibit it.
But you need to avoid situation when the user will be in storage very long time after closing the browser (one possible solution is short session timeout + keep-alive requests)
In your application, keep a timeout of the user that's updated after each call to the app. You can define the user as 'locked' into a session (for example your firefox session) until either the timeout expires, or the user requests a logout. When you log in on another browse (for example, chrome) it checks to see if there's an active session and, if there is, denies the login attempt.
I'm going to make up a quick example. This isn't even close to production ready and is for illustrative purposes only.
class User {
long lastCheckin;
int userId;
String username;
}
Now, when someone does anything in the app, like viewing a page, you do this
user.lastCheckin = System.currentTimeMillis();
Now, when someone specifically requests a logout, you do this
user.lastCheckin = 0L;
Now, when someone tries to log in, you do this
if(user.lastCheckin + PREDEFINED_TIMEOUT > System.currentTimeMillis()) {
return new LoginResponse(false,"User is active in another session.");
}
You can store a map of logged-in users on an application scope variable like a ServletContext. For example, on your auth servlet, you can probably do something like:
Map<String,String> activeUsers = request.getSession().getServletContext().getAttribute("__ONLINE_AUTHENTICATED_USERS");
//if null, context hasn't been prepared yet, create and attach a new one?2
You have to be careful though. Being an application scope variable, you need to ensure some thread safety and this is something which the servletContext.setAttribute/getAttribute is providing(e.g. those operations are not thread safe). You may be able to handle this by using some sort of application lifecycle listener to 'initialize' the servletContext to have the user map. This way you won't need to worry about the set/getAttribute. You still need to think about the map operations themselves(e.g. use j.u.c.ConcurrentHashMap maybe?).
You also have to take care of cleaning up(e.g. removing from the map) when a user logs out or session times out.
You also have to consider that a user might lock himself out for a long time by this approach(e.g. close browser but do not logout properly, session needs to timeout before the mapping is cleared).
Edit:
You also need to think about scalability and this depends on your application. Are you expecting a million online users? Or only a couple of thousands?
Now in my application cookies for users are generated in a certain format containing userID. I want my cookie to be generated randomly after every login so even if cookie were stolen once they would never be used forever by a hacker.
What is the best practice of handling cookies this way? How should I store/retrieve them(hashtable/datastore...)?
Thanks
I would recommend using the built in Java session objects HttpSession, which GAE/J has support for.
Look here for the docs on how to enable sessions on GAE.
You can set the session to expire after a certain time period, or you could store a number in it and verify the session externally.
You can try following parameters:
user id
time to live (milliseconds)
hash for:
user password
user id
remote IP or browser
time to live (exact same as before)
and maybe an predefined string or salt
Join it into one string (like 13413:1826271762:b026324c6904b2a9cb4b88d6d61c81d1) and store it into a cookie like USERID.
On every request you need:
check that specified time is valid (less than current)
load user from database, by specified ID
validate hash signature (against current remote IP/browser and current password)
I agree with Rick, the container designers have done the dirty work of verifying if the request is coming from the same user and you don't want to reinvent the wheel do you?
HttpSession session = request.getSession();
This will create a new session, if one doesn't already exists but if it does it will get you the existing session.
session.setAttribute('key', value);
value can be any Serializable POJO and key is a string.
You can retrieve the stored value within the scope of you application by following code.
Object value = (Object) session.getAttribute('key');
For more information on how to use sessions check Java spec for HttpSessions.
I have a web app in which I have set the maximum inactivity time to 10 min. This is just for testing purposes. Basically, if the session has timeout and I click on a link, the following window browser checks if the session is valid. This is also working fine. If this happens, I get a message saying "session has expired, please login again". But the orginal window stays open and if I click on the same link, then this time is letting me see the page, even though I have not logged in again. Why is this?
I am using the session.invalidate() if the session is expired, to make sure all attributes are removed, but this is not working somehow.
I using the following part of the code at the beginning of the page:
if(request.isRequestedSessionIdValid() == false)
{
response.sendRedirect("expired.jsp");
session.invalidate();
return;
}
This is working the first time this page is loaded, but if I click on the link again to load it once more, this condition is not met, despite the session being timeout.
Could you please give any advice?
Update: My webapp works the following way:
User gets to the index.jsp page and uses an ID and password to access the system, then there is a BRMspace.jsp page where there is a folder structure for the user to access depending on the documents they are after. By clicking on each folder, a table with a database populated is displayed for the user to download the documents they want.
The issue I am having is that after 10 min of inactivity, if the user clicks on one folder on the initial screen, the database is not displayed, instead I get a message saying that session has expired and I am redirected to the login page, which is ideal. However, if I click on the same folder again, this time I get the usual table with the data and all documents. It seems that after one click, the inactivity time is not longer valid.... so I am not sure how to do... I am using session.invalidate() to delete all data about the session, but obvioulsy is not working.
I need the user to be redirected to login page again after the inactivity time no matter where the user clicks on.
This is an update:
Hi there, I have to re-take this question, which has been very helpful to resolve 90% of my original issue, but I still have one left.... on my web application, when user logins, they have a list of options to click on, each click takes them to a new tab which are different .jsp files... if session has expired, these tabs show the expired.jsp file, which is perfect... however, the original tab, the one that is shown after the user logins, stays live, I mean, it does not show that the session has expired... what can I do in this case?...
A web session doesn't have anything to do with any login or access credentials. It simply means that the container has data saved for you that can be retrieved if you pass in the correct session token (either by cookie or request parameter). If you have been inactive on the site for a period of time (in your case 10 minutes), that data is discarded and if you check for a sessions validity, you will discover whether the data is still around or has been discarded. If the session has expired, the container will automatically create a new session for you to handle future requests. And if another request is sent to the server before the timeout expires, that requested session will not be invalid.
If you are trying to prevent people from access a page when they have not logged in, you actually need to put some value into the session that says they have authenticated, and check that value. Just checking whether their requested session is valid is not sufficient.
I have some PHP script that logs in and returns a JSON array with a session ID if the login was successful.
In my app, I want to login at the front page and continue out through the app being logged in. I created a singleton class that holds a session ID (along with a few other fields) received from the JSON from the PHP page. This singleton object's field "session_id" gets checked depending on what the user does.
If the user wants to log out, then the session_id just gets set to null thus logging out.
I also use the HttpURLConnection library to POST the username/password when logging in.
Is this a decent enough approach for handling this situation?
Here are some things you should think about:
Once you have authenticated the user and stored the session_id locally, send the session_id in the header of each of your http requests. That way, you're not sending the credentials with each request, but the session id. And if something happens on the server side to the session, the transaction will not be allowed.
When logging out, don't just delete the session_id on your app (client) side. Send a logout to the server as well so that the session can be killed server side.
If the session is killed on the server side, you'll want to do 1 of 2 things A) prompt the user to re-login. B) Use the store credentials to log back in, create a new session id and store it again in your singleton.
This will guarantee a bit more security and functionality than just clearing the session id on your app side.
This strategy will probably work. In an app I worked on, I stored the return data from login in the android shared preferences. If the user logged out, I cleared the preferences. This allowed users to stay logged in, even if they closed the app and went back in later. I had an authentication token that I checked to see if the user's login was still valid.
How do you plan on handling persisted logins? Does the sessionID expire? You might want to think about these situations otherwise once a user is logged in, they will be logged in forever or as long as the app is open.
The website is having auto-refresh.When an user login with the same username that is logged in already somewhere,how to logout the previous login?How to give a relogin page in the first browser window?
Please provide some code snippets....
Thanks in advance....
This post is dealing with a similar problem.
Without you specifying more details, it's difficult to answer your question properly. First of all, if a user opens another tab or window within the same browser, they will be still logged in using the previous login. This is normal behaviour.
If a user logs in using a different browser, then one thing you can do:
register a HttpSessionListener
when a session is created, using void sessionCreated(HttpSessionEvent se), check if user's credentials and session id are in your database
if not, put them in a database table
if yes, then invalidate their previous session by deleting previous credentials in database
when a session is destroyed, using void sessionDestroyed(HttpSessionEvent se) delete user's credentials in database
One other thing. If you're going to use this approach, then you'll have to check with every browser request if your user's credentials are stored in a database. You can use a Servlet filter for this. This will, of course, be an overhead.
One more thing. If there's an exception in your session creation/destruction code, there's a danger of user's credentials aren't properly disposed of in database. You can handle this using database triggers to delete rows that are as old as your session timeout is.