I'm building a Sails.js app that includes a user login. As the documentation instructs, when a user signs in, the session records her id in the session accordingly:
req.session.userId = createdUser.id;
In most of the examples, each route performs a lookup on this ID, if it's present, and sends the authenticated user to the view if found. This strikes me as very inefficient. EVERY view needs to know if there's a signed-in user in order to display her name in the upper left corner. So, if I understand right, every view includes a trip to the database to look up the user, even if I reduce the amount of code by creating a policy that performs this lookup for every route.
What I would rather do is record the user's information in the session so that, once she is authenticated, that information is automatically present to every view:
req.session.userId = createdUser.id;
createdUser.loggedIn = true;
req.session.user = createdUser;
// the createdUser object does NOT contain the encrypted password or other sensitive info
This then allows me to just check in the template for a signed-in user like so from the layout parent template (and any child template). (I'm using server-side views.)
{% if (session.user && session.user.loggedIn) %}
<li>Hi there, {{ session.user.username }}</li>
{% else %}
<li>Sign In (if you want)</li>
{% endif %}
My question is whether this poses a security risk of any kind. It seems MUCH more efficient than looking up the User in every view, but perhaps there's a reason that documentation seems to advise this?
In most of the examples, each route performs a lookup on this ID, if
it's present, and sends the authenticated user to the view if found
FYI, ideally this should be handled by a policy.
This strikes me as very inefficient. EVERY view needs to know if
there's a signed-in user in order to display her name in the upper
left corner. So, if I understand right, every view includes a trip to
the database to look up the user, even if I reduce the amount of code
by creating a policy that performs this lookup for every route.
Either you make extra roundtrips to the database or you bloat your sessions. Both have their pros and cons. E.g. when creating a backend application that does not have to scale, I do not care about this extra database lookups. However when I have hundred thousands of users I should care. You have to consider this when you architect your application. Applications that need to scale like to use e.g. redis as a session store for optimization.
So to answer your question, yes it is okay to store username etc. in the session object to avoid extra database lookups. I am not a security expert, but I would not suggest to store any sensitive user information in the session like passwords.
BTW I highly recommend using http://passportjs.org/. It integrates with sails very well.
To get you started:
http://iliketomatoes.com/implement-passport-js-authentication-with-sails-js-0-10-2/
https://www.airpair.com/express/posts/expressjs-and-passportjs-sessions-deep-dive
In this example you can see how username, email and the roles of the user are stored in the session object:
passport.serializeUser(function(user, done) {
var sessionUser = { _id: user._id, name: user.name, email: user.email, roles: user.roles }
done(null, sessionUser);
});
Related
I want to make multiple chatrooms like dynamic and I want to make them like this that if we refresh the page it retains the chat and users inside the rooms, I am new to socket.io and looking for the solution.
This is a pretty broad question so it's not really possible to be very specific with an answer. The general steps to retaining one or more "rooms" for a given user are as follows:
Install a session manager on your server. express-session is popular and you can then pick which data store you want to use with it (there are dozens of choices). This will give you a semi-persistent session object for each user who connects to your server.
When a user connects to your server for the first time, a session object and matching session cookie will be created that allows your server to identify that browser the next time it connects.
You can initialize a rooms property in that session to be an empty array or perhaps a Set object (which makes lookup a bit simpler for the later steps).
When this user gets put in a specific chat room, you add that room name to the session.rooms array or Set.
When the user leaves a specific chat room, you remove that room name from the session.rooms array or Set.
When a user re-connects, you look in their session and automatically join them to any rooms that the session says they should be connected to.
You probably need some sort of timeout process so that if a user remains disconnected for a certain period of time, you remove their session or at least clear their rooms list.
I find that some websites have sort of authentication even though no user is logged in. Taking plunker for example, even a non-logged in user can freeze a snippet such that other users cannot modify; whereas the user himself could always modify the snippet even though he opens the link in another browser tab.
My current solution is adding a type field (ie, anonym and normal) in the user model. Then, each time there is no normal user logged in, I systematically generate a unique random ID, register and login as an anonym user. It works, but the shortcoming is there are lots of anonym users in my database.
Does anyone have a better solution? Is there any "standard" way to realize this kind of hidden authentication?
I think method you are looking for is called session id. When you save as anonymous user web app creates a session with a session id which is used to identify the user by link. For example on plnkr it'll be something like https://plnkr.co/edit/session_id?p=catalogue where session_id is some sort of hash.
To freeze the snippet the session id is written into cookies with the flag, saying, for example, that the state is frozen. If you freeze it in Chrome and open in a Chrome's private window or in Firefox on the same computer, you wouldn't be able to unfreeze it. It'll behave the same way as for other users which have no cookies. In fact using session hash for cookies, rather than any user identification is better for security reasons.
Now this approach in a sense isn't any better, than creating anonymous users - you still have to save session records into the database to be able to open session context by link. In fact, it might happen to be simpler in your case to do exactly what you did if user is assumed to be present in lots of use cases and places in the code.
In many cases, however, separation of session from user makes lots of sense as it simplifies keeping session state after login or registration. Say some web stores would empty your basket after you register, causing quite a bit of frustration, especially if you put several small items into it which you now have to find again and put back. Those don't have sessions or don't use them correctly on registration or login.
Otherwise, as I wrote it's pretty much the same and you have to deal with many anonymous sessions which pollute the database unless you have some sort of wise retention policy, depending on you use case. Say, for example, a web site similar to plnkr.co which is used to share code snippets, and post them on sites such as stackoverflow should better keep those sessions while there are users accessing those say at least once a year. So sessions should have access date and policy would be that it's older than 1 year.
Hope it helps.
I have done similar using Local Storage. It allows you to store data on the browser. A user can then open tabs, close browser completely and reopen etc and the data is still there. It would then appear to be saved for them but actually it's just stored on their browser.
This wouldn't allow others to see what they have done though, so not sure if this is quite what you're after.
I wrapped them in functions in case I chose to change them out later, something like this
StoreLocalVariable: function (key, value) {
localStorage.setItem(key, value);
},
GetLocalVariable: function (key) {
return localStorage.getItem(key);
},
Some info including compatibility
https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
Building a web application.
User have access trough their browser to shared resources host on a server, however if UserA is already using Resource1, Resource1 should not be available to UserB until UserA release Resource1 or until a given amount of time.
For this part : I chose to use a MySQL table with a list of tuples (resource,currentuser) and run a cron task to delete expired tuples.
Now I want to be able to notify UserA that UserB wants to access Resource1 and if get not answer from UserA, then UserA lost his lock on Resource1 and then the Resource is then available to UserB.
For this part, I guess I have to use AJAX. I have thought about the following solution :
User's browser make periodic AJAX call (let's say each minute) to prove he is still alive and upon a call, if another User has requested the same resource, he has to challenge a server request in a given amount of time(for example a captcha). If the challenge fails, it means the user is not here anymore (maybe he left his browser opened or the webpage unfocused).
The tricky part is : "he has to challenge a server request in a given amount of time (for example a captcha)". How to do that?
Am I following the best path ?
Yes, what you've outlined is fine. Using ajax is also completely fine, especially if you're simply polling every minute.
For example, let's say you have the following:
setInterval(function() {
$.get('/resource/status', function(response) {
if (response.data.newRequest) {
//This would signal a new request to the resource
}
})
}, 60000)
When handling the new request to access the resource, you could use something like reCaptcha and display that however appropriate (overlay or inline). When you do this, you could also start a timer to determine if it's exceeded the amount of time allocated or not. If it has, then you can do another ajax request and revoke this person's access to the resource, or however you want to handle that.
i would use web sockets to control all the users that need to get the resource.
this way you will know who is connected and using the resource and when he finish using it you can let the next user the resource and so on ,
(this way can tell each user an estimation of how much time it will take him to get the resource and do some progress bar)
I think there're two problems here.
How to notify users that resource becomes available?
Periodic AJAX requests might be okay, but you can also consider long-polling or websockets to get close to notifying waiting users in real time.
How to find out that resource is still used by user?
If you want to catch the moment when human user is not doing anything on page, you can track mouse movement/clicking or keyboard button pressing. If nothing is done for last n minutes, the page might be considered as not active.
If you want to make sure that page is not exploited by automated software, you can ask to fill in captcha once in n minutes when resource is being used.
I am curious about the value of PHPSESSID because, I created a simple login-type web app. When I try to login with different accounts, the value of the PHPSESSID is not changing. I got curious if it does okay or not. Because I tried to login in youtube with different account too. But their SID's differ on each user.
My question is:
1) Is what happening on my web app okay ?
2) Is yes, how can I make a session ids per account/user ?
3) If no, how can I fix it ?
I would really appreciate your suggestions.
It partly depends on exactly how you implemented "login." One way to do it is simply to change the user-identity (which, by definition, is part of the data that is stored in the session), while keeping the same session.
Another equally-valid way to do it is to first update the existing session (to show that the user, in that session, is now "logged off") (maybe...), and then to coin a completely new session-id, thus starting an entirely new session, in which you now "log on."
One advantage of the second approach ... and probably the reason why so many sites do it this way ... has to do with the possibility that the user might wish to open a new browser-window, and to log-in to the application a second time, intending to keep both logins alive at the same time. If the session-id token is part of the URL, or maybe is part of a hidden form or what-have-you, such that both session-id's can be retained independently, it becomes possible for the user to do what he has done without conflict. Two parallel sessions exist. In one, he is logged on as "joe," and in the second, he is logged on as "jeff." And so on. One set of browser-windows (somehow ...) carries the "jeff session" token; others carry the "joe session" token.
Fundamentally, a "session" is just a pool of server-side values, identified by the (PHPSESSID ...) token furnished each time by the client. Exactly how you choose to manage it, is at your discretion. It's a design-decision with no "correct" approach.
I'm saving the user language choice into the sessions like this:
$this->session->set_userdata('language', $language);
And then I'm setting the language depending on the session data (and making a English , as a default language).
if ( !$language = $CI->session->userdata('language') )
{
$language = "english";
}
$CI->config->set_item('language', $language);
It works good, but the language that user has chosed lasts only for approx. 2 hours - then user have to pick the language again. So the question is, how can I extend the session time to expire (or make it expire only in case if user cleans up the browser data). I can not save the user choice in the database, because I need to also handle guests on my website.
I know I can extend the session time in the CI's config, but I just want it to happend only in case of the language selection, and not for example for accounts sessions.
It is the same session, and it either expires or doesn't. You can't have the authentication part expire, but not the language selection. CI doesn't make it easy to manage multiple sessions, which would have made it possible to store authentication in one short-lived session and language preference in a longer-lived one. As it is, it might be easier to just store language preference directly in a cookie; just keep in mind that you will have to set the cookie again on each request, otherwise it will not get refreshed automatically upon user activity and will expire even if the user is actively using the site.