Limiting user to one login session by unique ID in AuthCookie and checking against database table - c#

I am creating a website that lets users run tests and hosts study content, I do not wish for any logged in user to be able to have more than one logical session. So essentially restricting simultaneous usage from multiple browsers or computers logged into the same account by invalidating any requests coming from any non-current/latest session. But I am not too sure on how to best hook into this with asp.net forms authentication.
I am thinking:
Create a db table called ActiveSessions, with rows: UserID, UniqueSessionID. Store this UniqueSessionID in the encrypted AuthCookie on the client.
If a user is not authenticated and logs in via standard login page /account/login etc. Create new UniqueSessionID and store it in the AuthCookie and in the ActiveSessions table respectively, overwriting any existing value. I presume I would have to decrypt and copy contents of the default AuthCookie forms authentication will issue, then create a new AuthCookie using this copied data and also insert my UniqueSessionID into it before returning it to the client.
In the event a request comes in for which the AuthCookie holds a UniqueSessionID that does does not match the one in the database or the record is missing for the respective user, invalidate the session and redirect browser to login page or kill session and issue error for Ajax requests.
Create some kind of scheduled service that cleans up records in the ActiveSessions table based on where User LastActivityDate exceeds some length of time etc.
Ideally I am hoping forms authentication provides some hooks where I can stick this logic in and avoid doing this with attributes over controllers/methods etc.
Also I wish to avoid using session state and its cookie entirely.

I had a very similar requirement. My situation was such that I had to make sure that user ID's were logged in from just one device at a time (Forms Authentication, by the way, not AD). When a user ID tried to log in to another device while still logged in to an existing device, it killed the session on their existing device while allowing them to log-in to the new device. The implementation I created has worked perfectly and so far, have found no flaws in the design. I wrote up a solution on my original post on Stack Overflow:
When the same user ID is trying to log in on multiple devices, how do I kill the session on the other device?

Related

Kill user's session and logout through a interface menu

Can you advise me on how to kill somebody's session and make them logout from my MVC app.
My current plan is:
On the start of the app to load a SessionsCache
When user logins - save his session in tblSessions and partially reload the cache (add the session in it without making it call the DB)
Every 30 seconds an ajax will validate whether I have session or not
The administrator will have an interface tool containing all active sessions in the cache and when he kills a session he deletes it from the cache and DB
On the next ajax call the user wont have session and would be logouted
If a user logouts normally the session in the cache and DB will be deleted
Every 30minutes a full reload on the cache would be done
Please consider that my application has OnActionExecuting() overriden function which checks if the user has session and if not loggouts him.
But this happens only on action execution and if the user doesnt click anywhere (afk) he wouldn't be redirected to home page. (considering maybe the ajax call to check session is redundant?)
Also i want to clear user session when he closes the browser/tab without using the LogOut button but I am not sure how can this happen
There's a few issues with your proposed solution that makes it unworkable:
Both sessions and auth employ client-side cookies to manage their status. The server can only invalidate the authentication/session. It cannot actually "log out" a user directly, because that piece is not under direct server-control. In other words, you can set up something that says that a particular user should be logged out, but that user will not actually be logged out until they attempt to make another request and some check is performed by the server which then affects that status change on the user at that time.
Sessions employ sliding timeouts. That means any request the client makes will reset the timeout of their session. In other words, if you long-poll the session status every 30 seconds, the user will effectively have a perpetual session that will never ever expire.
Sessions are intentionally anonymized. For security reasons, the client's only link to their session is the cookie with their session id. This prevents a certain level of session hijacking by making the cookie a must-have component in a successful attack. With things like the Secure token, then, and of course utilizing SSL on your site, you can effectively prevent that cookie from being usable in any other context than the client it was assigned to. The long and short is that there's not really any way to figure out which session belongs to a given user outside of direct contact with that user.
Cache is by nature volatile. You can say that particular key should have a lifetime of some period, but that's merely a suggestion. There's any number of different factors that could cause a cached item to be destroyed, most completely outside of your control.
Given all that that, you must approach this from a different direction. My suggestion would be to have a separate table where you track logins/sessions, in a generic sense. It would basically be a kind of log. When a user logs in or creates a new session, you would add a record to this database. If the user's auth or session expires, you would update the appropriate record. If the user deliberately logs out, you'd delete the record or otherwise mark it as inactive. As far as your admins go, they would then manage this table, removing or marking records as inactive.
Then, you will have to add some logic around your site actions to account for this table. You could create an action filter that checks this table and performs any necessary operations. For example, if the user has been "signed out" by an admin, the action filter would read the appropriate record from this table, see that the user had been signed out, and then affect that change by actually signing the user out.
Since long-polling will cause the session to never expire, you would essentially need to manage your own timeout. For example, you could record the time the session was created in the "log" table, and then compare that time with the current time on each subsequent request (including AJAX). Again, you could employ an action filter for this purpose. If the session is "expired" based on your timeout, then you could manually destroy the user's session.
There's plenty of other things you'd need to add or account for in this way, but hopefully that gives you a good framework to work from.

Allow only one concurrent login per user in ASP.NET

Is it possible to allow only one concurrent login per user in ASP.NET web application?
I am working on a web application in which I want to make sure that the website allows only one login per user at a time. How to check that the current user already logged in or not?
Please suggest proper login method by which we can handle this problem. I think we should use SQL Server session state to handle this problem. What do you suggest?
I thought of one solution for it. We can do something like:
When the user logs into the system then we insert session id in user column. (We will use database session so that we can get all session related data like isexpired, expiredatetime etc easily).
When the same user tries to login a second time then we will check for that session id column and check that session is already expired or not. If session is not expired then we will not allow user to login.
Update user session ID every time when user logs out.
Please suggest whether this is the proper way or not.
Please refer to:
When the same user ID is trying to log in on multiple devices, how do I kill the session on the other device?
Out of the box, .NET does not support this. .NET allows for concurrent log-ins, as I'm sure you're aware.
I had this same exact requirement, and came up with a pretty slick solution, demonstrated in the link above. In a nutshell, my requirement was to only have one user log-in happening at one time. If that same user ID tried to log in elsewhere, then it killed the session for the first log-in by checking for an existing log-in under a different Session ID (this enabled the user ID to be logged in from multiple instances of their web browser on their computer [same Session ID], which is common, but not from a different computer [different Session ID] (possibly due to someone that stole their credentials, for example)). Through modification of the code you could probably change the behavior of this - i.e., prevent the second log-in attempt instead of killing the first log-in that's already active and in use.
Of course, it may not fit 100% to what you're needing, so feel free to modify it to fit your needs.
You can create a cache entry per user and store their session ID in it. Session ID will be unique per browser session. In your login page, you can create that cache entry when they successfully login:
if(Cache.ContainsKey["Login_" + username])
// Handle "Another session exists" case here
else
Cache.Add("Login_" + username, this.Session.SessionID);
(Code typed in textbox without syntax check. Assume "pseudo-code".)
In global.asax you can then hook into the Session_End and expire that cache entry of the user. See this for the global.asax events.
if(Cache.ContainsKey["Login_" + username])
Cache.Remove("Login_" + username);
You could add a flag column in the user table that indicates that a user is currently logged in.
When a users attempts to log in you check the flag if it's true (that users account is already currently used) then you don't allow the new user to log in, if the flag is false the users is allowed to log in as there account is not being used by anyone else at this time.
Be aware though that unless the uses actively logs out, you cannot know when the users moves on to something else (goes to different website or closes the browser, etc.) so you need to set some kind of session timeout that will automatically log out the user if there are no new requests within a specified time period.
This means that if a users closes his/her browser and try to log in on a mobile device for example, he/she will be unable to log in until your specified session timeout runs out, so give the timeout a bit of thought as you don't want the user to get logged out to quickly (if he/she is reading a long page, etc.) and you don't want the users to be unable to log in on another device for hours if he/she forgot to log out before leaving the home.
The login credentials are stored on the cookie, so to know if the user is logged in you need to keep this informations on server, prefered on a database because the database can be the only common place among web garden or web farm.
What you can keep, is on a table, that the user A is logged in or not, flag it that is logged out, maybe last user interaction to have a timeout, etc...
So let say that the User A, is logged in, then you open a flag on the database for that user, that is now logged in, and if is try to logged again, you keep him out.
To make this work you need to either say to your users to log out, or to keep a time out, similar to the time out of the credentials.
If You are using identity system this link will help you how to single user login on multiple device.
Prevent Multiple Logins in Asp.Net Identity
I have tried they work fine in my Asp.net Mvc Project.
Solution can be this way:
Add new column in your login table GuidCode.
Step 1 : When logging in check if the GuidCode in database is null.
Step 2 : Update GuidCode by new guid and also store it in the session.
Step 3 : If it is not null then take guid from the session and compare with database GuidCode value.
Step 4 : If it is same then allow login:

Different session Id from the same IP on the same time

In my application every time a user lands on my website I check that user with it's session ID and make a insert(with all the details ip,browser etc) into the database if its a different session ID.
string sessionId = HttpContext.Current.Session.SessionID;
if (objDB.checkDuplicate("session", "sessionId", sessionId))
{
// code to make insert in database
}
But when checking database I am getting multiple inserts from same IP at the same time.
Can anybody explain why this happens?
NOTE : SESSION of the user is different so checkDuplicate() works fine but how can a user have a different session ID at the same time? (or such a sort span of time)
Most probably it's multiple people sharing the same connection over a router or proxy server.
More reasons (being behind router/proxy is most likely one) to have different session Id for same IP
restarting browser will make new session Id for the same user (as long it is set in session cookies)
opening separate browsing session (i.e. normal vs. private for IE, depending on configuration and browser tabs may be treated as separate sessions)
different users on the same computer
Another set of reasons for different session Id is based on failure to set persist session cookie between requests:
I think if there is no writes to ASP.Net session state cookie can be regenerated on every request (need to verify)
cookie could be disabled (rare, but possible)
cookie can be blocked (i.e. lack of P3P policy for pages/images in IFrame) or some other policy in browser
There are valid reasons to get multiple browser windows for the same sessionId for the same user (tabs in same "browser session", "open in new window/tab" with Ctrl+click ). You as site creator have to decide if you want to try to enforce "single session = single window" policy or deal with potentially multiple windows opened in the same session. There is no reasonable way I know to detect case when same session Id is used in different tabs, especially if you have to support GET requests (otherwise you can dump some addition ID into hidden field).

Cookie safety issues

How can I remember a user that is logged in without having a security issue? Currently, I am storing the id and a guid into two different cookies and compare them when there is no session alive. If it match then I re-create the session. Btw, both id and guid are nore encrypted.
Is this method safe enough, or should I follow a rather distinct way?
Since cookies can be easily stolen by use of XSS, does not matter if you place information in just one cookie or two, because a theft will take them all.
I have solved with a more complex procedure: I place one encrypted cookie divided in 2 parts (but 2 cookies will work as well), one fixed and the other variable each session. Both are saved also on server side to check: they are only session identifiers, no sensible information contained in the cookie, the correspondence with the user id is saved on the server.
If a fake user enters the account with a stolen cookie, the variable part (or cookie) will change, so when real user connects again he will not be able to enter and you will have the proof that an unauthorized access occurred: then you can delete the permanent session on server side (defined by the fixed part or cookie) in order to avoid any further access by the theft. The real user will re-login and create a new permanent session with a new cookie. You can also warn him that you saw a security flaw, suggesting him to reset password (operation that should never be accessible directly from cookie) or to use another browser for unsafe navigation.
If you save additional user information (user-agent, IP by location) you can check cookie validity also on them in order to avoid even the first entrance of the fake user.
I would recommend you using forms authentication for tracking logged in users in an ASP.NET application.

authCookie and relogin the user

Scenario:
I have a tricky situation where need to keep many modules happy [Google Analytics, etc, etc...]. Got a asp.net page in the project which initiates the request on the third party website (after clicking the Process button) and redirects the user to the third party website. Transaction is processed on their website and then the control is returned back to the current page on our site. You can relate this scenario with kind of Paypal processing too, but it's not paypal.
Issue:
If the session is time out, I want the user to be again authenticated when the control reaches our website after the processing is done on the third party website. So I am thinking of passing the authCookie information to the third party website and then when the control reaches our website back, I will have the authCookie information (imagine it is the scenario) and then want to log the user back in. Can I do that by just creating an authCookie again based on the username?
It really depends on the transaction processing system you are using. If you check the result of the transaction by calling their API, then the response usually have a user id or something that you can tie to user id. You can store the user name in the cookie, cookies are per domain or subdomain and it won't get sent to the transaction processing web site if it is in the different domain than yours, which is most likely the case. Get or derive the user name from the transaction result response, compare it to the one you obtain from your cookie. If they match up, sign in the user. Signing the user in just based on the cookie contents is risky in many respects. First of all anyone can set the cookie with any name in it to the browser. Second, if you are signing in a user just based on a cookie, you'll basically get never expiring session. This is not what you want. For added security you can check the transaction time from the transaction result response and refuse to sign in if it was too long ago.
Oh, and in you question you mention that you "need need to keep many modules happy" but you do not expand on as to what you mean by this. So I'm just simply ignoring this bit. Not sure what a happy module look like =)

Categories

Resources