Unstealable persistent login cookie - cookies

Having read articles like http://jaspan.com/improved_persistent_login_cookie_best_practice I'm wondering whether there's a reasonably good way to achieve this.
So, what I want is to have a fairly hard time for a crook to steal a cookie, and use it in his own computer. Using secure cookies is out of the question. What I've been thinking about is to hash some information about the user's browser into the cookie, which would be verified once an auto-login is attempt.
So, the problem I'm facing right now is what info to hash. The browser name should be ok, but the version number would invalidate the auto-login on each browser upgrade. The same goes with feature sniffing. What I've been thinking of is hashing the browser name and the user's locale, to get a reasonable certain way of counteracting cookie theft.
Am I on the right track? Is there a de-facto way of doing this?
The system doesn't need to be 100% impregnable, just reasonably so.
PS: You don't have to worry about the other data in the cookie. I'm just curious about the "don't steal this cookie"-part.
Edit 1: A weakness in hashing client info, as I got answered elsewhere, would be that it's enough for the attacker to know that client info is used, and copy the client info as the cookie is stolen. Granted, an additional step to do for the attacker, but not as big a step as I imagined... Any additional thoughts?

First of all, there aren't any foolproof ways to deal with this, but I'll try to give you a more suitable answer. However, I'll start by some other things you probably should consider.
Start by thing about how to avoid a user's cookie being compromised in the first place. Probably the most common ways of cookie-jacking is either by listening to unsecured HTTP traffic, by using XSS attacks or by exploiting incorrectly defined cookie paths.
You mentioned that secure cookies are out of the question in your case, but I'll want to note this for further reference for other readers. Make sure your site uses HTTPS all the way, this way you will ensure that traffic to your site is secure even if the user is using an unencrypted wireless internet access.
Make sure your site defines the proper domain and path for the cookies, in other words, make sure that the cookies aren't sent to such part of the domain which shouldn't get access to the cookie.
Enable HttpOnly in your cookies. This means that your cookies are only sent on HTTP(S) requests and cannot be read, for example, by using JavaScript. This will mitigate the chances of the user's cookies being stolen by means of XSS.
That said, to answer your actual question, probably a common way of identifying the user by other means is by using browser fingerprints. A browser fingerprint is a hash which is built using unique information to the user's environment, for example, the fingerprint can include browser plugin details, time zone, screen size, system fonts and user agent. Note however, if any of these changes, so does the fingerprint, thus, in your case, invalidating the cookie - I don't necessarily see this as a bad thing, from a security point of view.

Related

How to protect web application from cookie stealing attack?

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.

Why do I see cookies I did not set?

I occasionally receive warnings from PHPIDS about certain cookies, and on further examination, it appears that a particular client keeps sending me cookies that I did not set, e.g. mp_d21cb8a9f34838c02aeec897b3728a94_mixpanel.
How is that possible? It was my understanding that cookies are only sent back to the server/domain that set it, and I do not use mixpanel and to my knowledge did not set that cookie.
I understand that mixpanel is a web tracking tool, but I do not use it (I use Google Analytics). I have no other users on my server/domain, I have no affiliate ads/banners on my site, and I do not support user generated content. So I am fairly certain that my server did not set that cookie, but then why does the client browser (IE11) keep sending me that cookie? The user's behavior seems legitimate, i.e. it appears to be no bot or script.
Do I have a fundamental misunderstanding how cookies work? Can some other server set cookies for MY domain? Any ideas how this comes about? Are there known browser bugs that mixes up cookies?
Regards,
Arno

Can the user agent be used to tie a cookie to hardware?

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.

Redirect returning users to specific page

This questions is more conceptual that asking for actual code.
I want to redirect returning anonymous users to a page other than the home page. Is there any other way to do this than to use a cookie? Is a cookie an ok way of accomplishing this? I'm worried about the reliability of cookies, but maybe I'm mistaken in questioning that.
Thanks for any help.
I would say create a session state instead if your worried about cookie reliance.
You can make the session state last a bit longer than default. Keep it as small as possible ie. a simple bool.
As long as the cookies stay on the same domain, they should be considered first-party cookies.
I think it is safe to assume that a significant large majority of browsers only reject 3rd party cookies.
Since security (it is on the client side and subject to attack) and filesize (cookies usually have a maximum size) do not seem to be an issue here, why not?
as you think about a security issue than it is better to use Session for this.
but if you want to use third-party cookie than take care of following points while setting up cookie.
Use persistant cookie (set expire date of cookie).
Create cookie with HttpOny parameter.
if your server using Secure Connection (ie. https) than use
Secure Cookie.

Does an HTTP Session always require a Cookie?

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.