My web application's authentication mechanism currently is quite simple.
When a user logs in, the website sends back a session cookie which is stored (using localStorage) on the user's browser.
However, this cookie can too easily be stolen and used to replay the session from another machine. I notice that other sites, like Gmail for example, have much stronger mechanisms in place to ensure that just copying a cookie won't allow you access to that session.
What are these mechanisms and are there ways for small companies or single developers to use them as well?
We ran into a similar issue. How do you store client-side data securely?
We ended up going with HttpOnly cookie that contains a UUID and an additional copy of that UUID (stored in localStorage). Every request, the user has to send both the UUID and the cookie back to the server, and the server will verify that the UUID match. I think this is how OWASP's double submit cookie works.
Essentially, the attacker needs to access the cookie and localStorage.
Here are a few ideas:
Always use https - and https only cookies.
Save the cookie in a storage system (nosql/cache system/db) and set it a TTL(expiry).
Never save the cookie as received into the storage but add salt and hash it before you save or check it just like you would with a password.
Always clean up expired sessions from the store.
Save issuing IP and IP2Location area. So you can check if the IP changes.
Exclusive session, one user one session.
Session collision detected (another ip) kick user and for next login request 2 way authentication, for instance send an SMS to a registered phone number so he can enter it in the login.
Under no circumstances load untrusted libraries. Better yet host all the libraries you use on your own server/cdn.
Check to not have injection vulnerabilities. Things like profiles or generally things that post back to the user what he entered in one way or another must be heavily sanitized, as they are a prime vector of compromise. Same goes for data sent to the server via anything: cookies,get,post,headers everything you may or may not use from the client must be sanitized.
Should I mention SQLInjections?
Double session either using a url session or storing an encrypted session id in the local store are nice and all but they ultimately are useless as both are accessible for a malicious code that is already included in your site like say a library loaded from a domain that that has been highjacked in one way or another(dns poison, complomised server, proxies, interceptors etc...). The effort is valiant but ultimately futile.
There are a few other options that further increase the difficulty of fetching and effectively using a session. For instance You could reissue session id's very frequently say reissue a session id if it is older then 1 minute even if you keep the user logged in he gets a new session id so a possible attacker has just 1 minute to do something with a highjacked session id.
Even if you apply all of these there is no guarantee that your session won't be highjacked one way or the other, you just make it incredibly hard to do so to the point of being impractical, but make no mistake making it 100% secure will be impossible.
There are loads of other security features you need to consider at server level like execution isolation, data isolation etc. This is a very large discussion. Security is not something you apply to a system it must be how the system is built from ground up!
Make sure you're absolutely not vulnerable to XSS attacks. Everything below is useless if you are!
Apparently, you mix two things: LocalStorage and Cookies.
They are absolutely two different storage mechanisms:
Cookies are a string of data, that is sent with every single request sent to your server. Cookies are sent as HTTP headers and can be read using JavaScript if HttpOnly is not set.
LocalStorage, on the other hand, is a key/value storage mechanism that is offered by the browser. The data is stored there, locally on the browser, and it's not sent anywhere. The only way to access this is using JavaScript.
Now I will assume you use a token (maybe JWT?) to authenticate users.
If you store your token in LocalStorage, then just make sure when you send it along to your server, send it as an HTTP header, and you'll be all done, you won't be vulnerable to anything virtually. This kind of storage/authentication technique is very good for Single-page applications (VueJS, ReactJS, etc.)
However, if you use cookies to store the token, then there comes the problem: while token can not be stolen by other websites, it can be used by them. This is called Cross-Site Request Forgery. (CSRF)
This kind of an attack basically works by adding something like:
<img src="https://yourdomain.com/account/delete">
When your browser loads their page, it'll attempt to load the image, and it'll send the authentication cookie along, too, and eventually, it'll delete the user's account.
Now there is an awesome CSRF prevention cheat sheet that lists possible ways to get around that kind of attacks.
One really good way is to use Synchronizer token method. It basically works by generating a token server-side, and then adding it as a hidden field to a form you're trying to secure. Then when the form is submitted, you simply verify that token before applying changes. This technique works well for websites that use templating engines with simple forms. (not AJAX)
The HttpOnly flag adds more security to cookies, too.
You can use 2 Step Authentication via phone number or email. Steam is also a good example. Every time you log in from a new computer, either you'll have to mark it as a "Safe Computer" or verify using Phone Number/Email.
Related
I have two web applications different things, but authentication is done only by one (using python and tornado), id like to have the second application access the credential of the user transparently, currently I can read the cookie of a logged in user via the header: Access-Control-Allow-Credentials , so how would i access the cookie, so i can store it (mongodb/redis/anywhere-but-mysql), and retrieve it in the second app?
what I've tried:
self.set_secure_cookie('cookie_name') # works i can see the cookie in subsequent request headers
self.get_secure_cookie("cookie_name") # just after setting the cookie returns None
what I was thinking is to store the encrypted value and compare it later in the second application as and when needed, is this sensible? all that i need to do is to ensure the user is
logged in and they exist in out list of users as of the moment.
So you've managed to set a cookie by one of the servers and then retrieve it on the second? If so, great! That's the trickiest part (imho).
Now there are two ways to go.
Store data in the cookie
Tornado have, as you've noticed, support for secure cookies. This basically mean that you can store data in the cookie and sign it with a secret. If both you servers have the same secret they can verify that the cookie data is not altered and you have successfully distributed data between the two servers. This decentralised alternative is not suitable if you need to store much data in the session.
A shared DB (or an API that the other server can use)
If you go with this solution you just have to store a session key in the cookie. No need to use secure cookie since it's no data stored there. You simply generate a SSID, e.g. ssid = uuid.uuid4().hex, store that in a cookie called something like ssid and also add a record to the DB along with all session data you want to store. I really like Redis for this since you can set the expire on creation and don't have to worry about that anymore, it's pretty fast and the best thing is that there's a nice and easy async lib you can use that plays nice with tornado.
I help maintain a site that is sold to about 100 clients. We take security pretty seriously and we have a multiple step login process. One part of the process can be skipped if you have already logged in before and choose to get a cookie. When you login again and still have that cookie, that step is skipped. Of course, the value in the cookie is random and different for every user.
My boss wants to make it impossible to copy the cookie to another computer. Of course, I've explained that is not possible, but he still insists it is by requiring the user agent to remain the same.
"We can then document that we have a “hardened” cookie that is specific to the user’s hardware and software."
Of course, I've explained that spoofing the user agent would be many many times more easy to do than spoofing the cookie value, and compared it to putting a band-aid on a padlock. Not to mention any opportunity you have at copying the cookie would allow you to copy the user agent as well. He doesn't care.
It doesn't bother me to require the same user agent but I have some integrity and a problem working on something being sold with such a lie about its security.
I'm a professional not a grunt. I wouldn't design a bridge that supports one weight when I know will be advertised as supporting a higher weight.
Am I being reasonable?
Suggest an alternative, since cookies are not intended to provide security:
*
An active network attacker can overwrite Secure cookies from an insecure channel, disrupting their integrity
Transport-layer encryption, such as that employed in HTTPS, is insufficient to prevent a network attacker from obtaining or altering a victim's cookies because the cookie protocol itself has various vulnerabilities.
A server that uses cookies to authenticate users can suffer security vulnerabilities because some user agents let remote parties issue HTTP requests from the user agent (e.g., via HTTP redirects or HTML forms). When issuing those requests, user agents attach cookies even if the remote party does not know the contents of the cookies, potentially letting the remote party exercise authority at an unwary server.
Cookies do not provide integrity guarantees for sibling domains (and their subdomains). For example, consider foo.example.com and bar.example.com. The foo.example.com server can set a cookie with a Domain attribute of "example.com" (possibly overwriting an existing "example.com" cookie set by bar.example.com), and the user agent will include that cookie in HTTP requests to bar.example.com. In the worst case, bar.example.com will be unable to distinguish this cookie from a cookie it set itself. The foo.example.com server might be
able to leverage this ability to mount an attack against bar.example.com.
Cookies rely upon the Domain Name System (DNS) for security. If the DNS is partially or fully compromised, the cookie protocol might fail to provide the security properties required by applications.
References
Sharing a Session across multiple domains
RFC 7258: Pervasive Monitoring is an Attack
A cookie that has a signature involving a server side "secret" and using the user agent as part of the salt will be more difficult to spoof, than a cookie that does not have the user agent as part of the salt. That is indisputable. First of all, it takes time to figure out how the salt is created - and a lot of "attackers" will be discouraged immediately.
Yes, but it is not more secure...
Your boss has a goal; to be able to tell his customers that the cookie is "hardened". You shouldn't assume that your boss does not understand the implications.
The fact is; it won't affect your applications security at all in either direction. It will however result in the cookie being slightly more difficult to move from one machine to another, and it will make the cookie stop working if the client updates his browser or flash version or changes his user agent in other ways.
Conclusion:
If everything else is equal, I consider the user agent salt in cookies as better than no user agent salt, by a tiny amount. I guess you could implement the thing faster than the time you spent asking this question.
I have a RESTful API which has annotations like #Consumes(MediaType.JSON) - in that case, would the CSRF attack still be possible on such a service? I've been tinkering with securing my services with CSRFGuard on server side or having a double submit from client side. However when I tried to POST requests using FORM with enctype="text/plain", it didn't work. The technique is explained here This works if I have MediaType.APPLICATION_FORM_URLENCODED in my consumes annotation. The content negotiation is useful when I'm using POST/PUT/DELETE verbs but GET is still accessible which might need looking into.
Any suggestions or inputs would be great, also please let me know if you need more info.
Cheers
JAX-RS is designed to create REST API which is supposed to be stateless.
The Cross Site Request Forgery is NOT a problem with stateless applications.
The way Cross Site Request Forgery works is someone may trick you to click on a link or open a link in your browser which will direct you to a site in which you are logged in, for example some online forum. Since you are already logged in on that forum the attacker can construct a url, say something like this: someforum.com/deletethread?id=23454
That forum program, being badly designed will recognize you based on the session cookie and will confirm that you have the capability to delete the thread and will in fact delete that thread.
All because the program authenticated you based on the session cookie (on even based on "remember me" cookie)
With RESTful API there is no cookie, no state is maintaned between requests, so there is no need to protect against session hijacking.
The way you usually authenticate with RESTFul api is be sending some additional headers. If someone tricks you into clicking on a url that points to restful API the browser is not going to send that extra headers, so there is no risk.
In short - if REST API is designed the way it supposed to be - stateless, then there is no risk of cross site forgery and no need to CSRF protection.
Adding another answer as Dmitri’s answer mixes serverside state and cookies.
An application is not stateless if your server stores user information in the memory over multiple requests. This decreases horizontal scalability as you need to find the "correct" server for every request.
Cookies are just a special kind of HTTP header. They are often used to identify a users session but not every cookie means server side state. The server could also use the information from the cookie without starting a session. On the other hand using other HTTP headers does not necessarily mean that your application is automatically stateless. If you store user data in your server’s memory it’s not.
The difference between cookies and other headers is the way they are handled by the browser. Most important for us is that the browser will resend them on every subsequent request. This is problematic if someone tricks a user to make a request he doesn’t want to make.
Is this a problem for an API which consumes JSON? Yes, in two cases:
The attacker makes the user submit a form with enctype=text/plain: Url encoded content is not a problem because the result can’t be valid JSON. text/plain is a problem if your server interprets the content not as plain text but as JSON. If your resource is annotated with #Consumes(MediaType.JSON) you should not have a problem because it won’t accept text/plain and should return a status 415. (Note that JSON may become a valid enctype one day and this won’t be valid any more).
The attacker makes the user submit an AJAX request: The Same Origin Policy prevents AJAX requests to other domains so you are safe as long as you don’t disable this protection by using CORS-headers like e.g. Access-Control-Allow-Origin: *.
I have this one question in mind that in login sessions does client have to maintain anything so that server uniquely identify client and in multiple client requests response to correct client. I don't understand this sessions and cookies. I asked many about this some say that its server job to maintain sessions and client just send normal request.
Yes, the client must keep track of something, called a session ID. Most commonly, it is a cookie. However, a less used approach is to rewrite all links to pass the session ID in the URL.
Example ID names are ASP.NET_SessionId and PHPSESSID.
Matthew's answer is correct.
It is the server's job to keep track of login sessions, and it's the client web browser's job to keep track of cookies. When you provide username & password on a site, a cookie is provided by the web server to your browser, which will automatically be provided along with subsequent requests to the web server. This cookie uniquely identifies a session which belongs to a particular user on the site (even the "guest" user). So, the server keeps track of all client sessions, and each client remembers its session cookie & provides it along with all its requests. It's a simple scheme. Using Firebug for example, you can see what the web requests look like when you log into a site. You might find that interesting to look at.
It is the server which will maintain the sessions. And it is the server responsibilty to allow session tracking happen. Clients need not bother about sending any information explicitly. As Cliens also sends Cookies saved on the client along with every request, server might use Cookies for sesssion tracking.
Note: Cookies are just one of the way to implement Session Tracking. It is also the best way
So server Cookies as one of the ways to handle session tracking.
It can also be done in other ways:
URL rewriting - the application/server should append the session id in all URL's/Links. When those are invoked from the client the session comes to the server along with the URL.
Hidden Form Fields - The forms may contain hidden input type with session id as field value. When the form is posted, the session id comes along with the form data.
I'm guessing Yes, but I'm not sure.
Both Authenticated Sessions and Anonymous Sessions would reference the stored sessions via the cookie.
########### edit: Clarify
It seems that sessions require some way of referencing for the stored session data.
This reference could be stored in a cookie OR added as a parameter in the URL.
I know this is taking you too literally, but it seemed appropriate to point out that HTTP is stateless and therefore does not have sessions. In order to maintain state, either the browser or the server have to persist the state information between requests. Traditionally, the server maintains the state, and by convention this is called a session, but it has nothing to do with HTTP as it is a workaround. Also, a session usually has a very specific connotation to it - namely that it is an individual visit to the site that will expire when it is no longer being used (some period of inactivity). It will also be different for the same user using different computers or browsers.
In order to achieve a server session, the server will generally set aside some information in memory or database to keep track of state and use a piece of identifying information to associate http requests with that state. This is usually a token. The browser needs to include information identifying the session with each http request. It doesn't matter how this happens, as long as the server and browser agree. It is most often a cookie, or url parameter as fallback, but as long as you set up the code right it could also be part of the url itself, part of a POST body, or even a non-standard http header.
The alternative that is becoming more and more popular is to maintain state in the browser and use purely ajax calls to the server. In this scenario, the server does not have to maintain any concept of session, and will simply return the data that is requested in a completely user-agnostic way. Some authentication may still be needed if the data is private, but a session token is not, and no state is kept on the server.
You can pass the session ID around as a query parameter (www.blah.com/index.php?SESSIONID=fADSF124323). But it has to be on every page. PHP has a option to enable this transparently. It is a huge mess. This is why cookies are preferred.
Not necessarily, some sites use a session ID value present in the URL that represents the session and this value gets appended to all links visited by the user.
We have to use it this way at work, since often mobile browsers don't accept cookies and this is the only way to remember a session.
Also there is HTTP-Authentication, not used often anymore today as the browser has to send username and password to the server unencrypted on every request.
HTTP-Auth just puts username and password in the header sent by your browser.
you can pretty much uniquely identify people by their browser plugins, fonts, etc.
https://panopticlick.eff.org/
When you're using SSL/TLS, then you could at least theoretically use the SSL session id to reference some state on the server.