I'm working on a website where I get a feed of usernames / hashed passwords from another service. When someone sucesfully logs in I set a forms authentication cookie with FormsAuthentication.SetAuthCookie.
My client doesn't like multiple people logged with the same credentials. They would like a log in to invalidate any currently logged in clients.
There isn't a method on FormsAuthentication to tell the server "invalidate any other cookie under this name". KB900111 suggests the server doesn't maintain a list of valid cookies. So my approach isn't sounding good.
What's the alternative? Time to ditch forms auth?
Not necessarily. Forms auth still provides quite a bit of baked-in functionality you might want. Maybe you can generate and issue a Guid the first time each user logs in, and store that on the server-side, and in a cookie (security ticket preferably). Every time a request is made, you check to make sure the user is using not only the correct credentials, but also the same machine and browser (based on the cookie you issued the user when the user logged in). You would of course have to make sure that your Guid expires at some point, and also make sure you clear it out when the user signs out.
Related
How to protect GET methods if the cookie is stolen since Antiforgery Token only protects the POST methods? The web application can return sensitive information via GET method.
I am using .AspNetCore claim based identity. I was trying to use Postman to view the content of the GET method, but I cannot get the it to work.
I assume this is theoretically possible. An authorized user cookie can be hijacked by a man sit in middle right?
The site is secured by SSL and I think the .AspNetCore claim based identity is session based cookie. What are the chances to break in to execute the GET methods and get returns values. How to secure the application?
It should never get to that point
Don't use just a cookie to validate a user. You should use several cookies based on each session, such as the device name or id, the device's IP address, a session ID stored in their browser, potentially something stored in their local data (permanently stored even if cookies are deleted) that validates that particular PC etc. There are plenty of other methods of security a user's identity.
However, if you use a session cookie and nothing else to authenticate a user, then you should probably revise how your application secures its users first. Because if that session cookie is stolen, then it's a bad sign for your user.
Is there a way to remove the authentication cookie, or sign a user out once they are removed from the asp.net membership database? By default if a user is removed from the database, the user can still browse the website since they still have a valid authentication cookie.
I've tried different things within global.asax but nothing seems to work. Is something like this even possible?
See here: FormsAuthentication.SignOut Method. Although this refers to users not being logged out server side, a similar approach can be used for managing deleted users.
Calling the SignOut method only removes the forms authentication cookie. The Web server does not store valid and expired authentication tickets for later comparison. This makes your site vulnerable to a replay attack if a malicious user obtains a valid forms authentication cookie. To improve security when using a forms authentication cookie, you should do the following:
Use absolute expiration for forms authentication cookies by setting the SlidingExpiration property to false. This limits the window in which a hijacked cookie can be replayed.
Only issue and accept authentication cookies over Secure Sockets Layer (SSL), by setting the RequireSSL property to true and by running the entire Web site under SSL. Setting the RequireSSL property to true ensures that ASP.NET will never send an authentication cookie to the browser over a non-SSL connection; however, the client might not honor the secure setting on the cookie. This means the client might send the forms authentication cookie over a non-SSL connection, thus leaving it vulnerable to hijack. You can prevent a client from sending the forms authentication cookie in the clear by running the entire Web site under SSL.
Use persistent storage on the server to record when a user logs out of the Web site, and then use an application event such as PostAuthenticateRequest event to determine whether the current user was authenticated with forms authentication. If the user was authenticated with forms authentication, and if the information in persistent storage indicates the user is logged out, immediately clear the authentication cookie and redirect the browser back to the login page. After a successful login, update storage to reflect that the user is logged in. When you use this method, your application must track the logged-in status of the user, and must force idle users to log out.
The third option is the most secure but requires the most effort. IMO, the first two do not resolve the issue adequately.
It is also possible to store custom information in the Forms Authentication Ticket. You could store the last explicit logout time in this ticket, and check it against your server side database record. Please note that if this record is at user level instead of session, then all logins under that account would be logged out at the same time.
In your case, if you are deleting server side user and session records, as the record does not exist you will be able to also fail the authentication request.
I'd advise also storing and checking the last date/time the password was changed - that way if a user updates their password then all existing sessions are logged out.
Instead of using ASP.NET MVC User's system, I'm simply using session, as the following:
When he logs in (username + password), I fetch the corresponding user from the Database and set:
Session["UserId"] = fetchedUser.UserId;
Then, I'm always checking if he is logged in:
if (Session["UserId"] != null && ...)
The problem is that if someone copies the value of ASP.NET_SessionId from a logged in user (eg: user goes to bathroom and coworker who is sitten next to him checks his cookies with chrome inspector), then he will be able to create a cookie in his computer and act as that user.
My questions are:
Why are sessions safer than cookies if the session id is saved in a cookie?
Can I make this safer (and continue using session)?
How does internally ASP.NET User authetication system do it?
A primary reason for not using Session as an authentication mechanism is that it could render your application vulnerable to Session Fixation. For example, a problem could be if a user arrived on your site using the HTTP protocol and receives a session ID that is stored in the ASP.NET_SessionId cookie. The user may later log in, and even though your login pages might be secured under HTTPS the session token has already been generated under HTTP which means it has already been transported using cleartext.
To answer your other points:
Why are sessions safer than cookies if the session id is saved in a
cookie?
The data stored in session is stored server side, so it is more difficult for an attacker to tamper with this data. All the cookie stores is a token for this data, rather than the data itself. Having said that, it is still safer to use the FormsAuthenticationProvider as this creates a new authentication token once login is complete rather than on session start for the reasons of avoiding session fixation as above.
Can I make this safer (and continue using session)? How does
internally ASP.NET User authetication system do it?
The built in provider is already fit for purpose, so it would be desirable to use that rather than fudge another mechanism to meet your requirements. It is also easily extensible so you can customise it to your needs. The ASP.NET User Authentication creates an encrypted ticket and stores it in the cookie rather than storing a reference to a server side variable: http://support.microsoft.com/kb/910443
I would also draw your attention to the signout mechanism and how to secure it. Particularly
Calling the SignOut method only removes the forms authentication cookie. The Web server does not store valid and expired authentication tickets for later comparison. This makes your site vulnerable to a replay attack if a malicious user obtains a valid forms authentication cookie.
Details here: http://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.signout.aspx
In addition you may want to set the "secure" flag on your ASP auth cookie to prevent it being leaked over HTTP by a MITM attacker.
In asp.net, I am able to login using forms authentication as usual, copy our auth cookie value, log out, add the cookie artificially to the client using the 'Edit This Cookie' addon for Chrome, refresh the (anonymous) landing page and hey presto i'm logged in again. This seems to be a vulnerability - is there any way of fixing it using the the standard forms auth or will I have to do something like use a custom Authorize attribute which overrides the existing one in asp.net mvc?
I don't think this is a bug per se. The following happens during forms authentication
You provide a username/password to the server
Server validates username/password
If valid, the server then sends an encrypted authentication ticket (cookie) to the client with the expiration time (set in the web.config forms authentication section) and username (all encrypted)
On each request that requires authorization, the cookie is decrypted on the server, expiration time is checked and username is used to see if authorized (or getting that role for the requested resource).
When you logout, the expiration time on the cookie is set in the past, therefore, it is not longer a valid cookie
Now, as to why you are seeing what you are seeing... You are copying the cookie before you logout. Thus your copied cookie never registers the logout (moved expiration time). When you reattach, you still have a valid auth cookie. Now, if your forms authentication timeout is set to...let's say 20 minutes...this method would fail if you copy the cookie and wait 21 minutes as by that time, it has expired.
Cookies are always vulerable and we can't do much about that. What we can do is prevent someone from stealing the cookies.
Regarding ASP.NET MVC it does a good job to avoid stealing cookies. Some of the main things it does by default as part of security are:
Encode the strings that are rendered to the view (if you are using Razor don't know about others) to prevent from XSS attacks.
Request validation (stop potentially dangerous data ever reaching the
application).
Preventing GET access for JSON data.
Preventing CSRF Using the Antiforgery Helpers
Regarding cookies Microsoft provides HttpOnly feature and this helps to hide the cookies from javascript. The Forms authentication that you are talking about is a HttpOnly cookie means someone can't steal that through JavaScript and it's more safe.
You can do that with any cookie/s. You can inspect/copy all the cookies from any given domain, and spoof if you want. You can do that to yourself (only) because its your PC (or user logged in to PC). Obviously if you're on a shared PC, that is a problem (across all your info).
The act of "copying your cookie" is in fact one way malware attempts to steal/hijack your identity (or current session on some web site). That said, unless you have some malware, you can't just "copy cookies" of someone else.
Assuming logout is done, you can ask users to close their browsers so the expired cookie is removed from the (file) system.
Reading this question,
Different users get the same cookie - value in .ASPXANONYMOUS
and search for a solution, I start thinking, if it is possible for some one to really steal the cookie with some way, and then place it on his browser and login lets say as administrator.
Do you know how form authentication can ensure that even if the cookie is stolen, the hacker does not get to use it in an actual login?
Is there any other alternative automatic defense mechanism?
Is it possible to steal a cookie and
authenticate as an administrator?
Yes it is possible, if the Forms Auth cookie is not encrypted, someone could hack their cookie to give them elevated privileges or if SSL is not require, copy someone another person's cookie. However, there are steps you can take to mitigate these risks:
On the system.web/authentication/forms element:
requireSSL=true. This requires that the cookie only be transmitted over SSL
slidingExpiration=false. When true, an expired ticket can be reactivated.
cookieless=false. Do not use cookieless sessions in an environment where are you trying to enforce security.
enableCrossAppRedirects=false. When false, processing of cookies across apps is not allowed.
protection=all. Encrypts and hashes the Forms Auth cookie using the machine key specified in the machine.config or web.config. This feature would stop someone from hacking their own cookie as this setting tells the system to generate a signature of the cookie and on each authentication request, compare the signature with the passed cookie.
If you so wanted, you could add a small bit of protection by putting some sort of authentication information in Session such as a hash of the user's username (Never the username in plain text nor their password). This would require the attacker to steal both the Session cookie and the Forms Auth cookie.
The scenario where a cookie can be stolen happens in a public wireless environment. While you or I would never operate in such a setup, it may be impossible to prevent your customers from doing so.
If the attacker knows what secure site you're connected to, the idea is that your browser can be tricked into posting to a non-secure version of the same url. At that point your cookie is compromised.
That's why in addition to httpOnlyCookies you'll want to specify requireSSL="true"
<httpCookies httpOnlyCookies="true" requireSSL="true" />
I disagree with The Rook's comment, in that I find it unfair;
#Aristos i updated my answer. But to be honest, if your using a Microsoft development platform your application will be inherently insecure. – The Rook 22 mins ago
Security doesn't happen by accident and it doesn't happen "right out of the box", at least not in my experience. Nothing is secure until it's designed to be so, regardless of the platform or the tools.
There are many ways that a session id can be leaked to an attacker. XSS is the most commonly used attack to hijack a Session ID and you should test for XSS vulnerabilities in your application. . A common method of improving the strength of a session is to check the IP address. When the user logs in, record the ip address. Check the IP address for every request, if the IP changes then its probably a hijacked session. This secuirty measure could prevent legitimate requests, but that is very unlikely.
Do not check the X-Forwarded-For or User-Agent, its trivial for an attacker to modify these values.
I also recommend enabling httpOnlyCookies in your web.config file:
<httpCookies httpOnlyCookies="true"/>
This makes it more difficult for an attacker to hijack a session with javascript, but its still possible.
I don't know the specifics of the cookie in question but it's generally bad practice to store both the username and password in a user cookie. You generally want to only store the username in the cookie along with other non sensitive information. That way the user is prompted to provide their password only when logging in.
I am working on this, and I am coming up with an idea, that I am not sure if it is 100% safe, but is an idea.
My idea is that every user must pass from the login page.
If some one stole the cookie, is not pass the login page, but is go direct inside to the rest pages. He can not pass the login page, because did not know the really password, so if he pass he fail anyway.
So I place an extra session value, that the user have been pass with success the login page.
Now inside every critical page, I check that extra session value and if found it null, I login off and ask again for the password.
Now I do not know, maybe all that done all ready by microsoft, need to check it more.
To check this idea I use this function that direct make a user logged in.
FormsAuthentication.SetAuthCookie("UserName", false);
My second security that I have all ready fix and use, is that I check for different ips and or different cookie from the same logged in user. I have made many think on that, many checks (if is behind proxy, if is from different countries, what is look for, how many times I have see him, etc...) but this is the general idea.
This video show exactly what I try to prevent. By using the trick I have describe here, you can not just set the login cookie only.
Just sharing my ideas...