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

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.

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.

How to protect session against theft?

Simple test:
On one machine I am logged to site (https)
I entered to the same page on different machine (not logged in)
I switched session_id in header on second machine - from first machine
On second machine I get all of first machine - I am logged in, can easily browse its data, etc.
How to protect session (and maybe csrf token) against theft?
Make sure your session keys are unguessable. a GUID/UUID works ok here (or better, hash the output of a crypto random number generator).
Make sure the Id is never transmitted in plain text (use SSL)
Update your session Id frequently (say every 5 minutes or so).
By doing the above, it should be impossible for an attacker to intercept the session id. It's also a good idea to use secure Cookies. This will prevent the cookie being sent for non-secure resources (eg loading images/css via http which doesn't require authentication)
You can optionally try to tie a session to an IP address but that's not a perfect solution. It fails to defend against an attacker behind same NAT as the user, and can fail to authenticate a valid user who has multiple routes to the internet.
To clarify: You will always be able to see your own session id. The trick is making sure nobody else can see it. It's effectively a temporary password. Secure cookies are encrypted on disk by most browsers (reversible). It's encrypted again for transmission over SSL to the server.
Assuming you're talking to the right server [a different issue], the only way an attacker can get your session id is to either install malware on your machine or break Ssl.
Frequent changes to the id mean an attacker will only have a short window before they must start over.

Unstealable persistent login cookie

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.

Should services ask for credentials at each request?

I wonder what is the optimal authentication method for services and webservices:
user/password is sent on each request
user/password is sent once to obtain an authentication code that will be sent on each request
Is there any alternative? Which is better? Why?
Depends on the protocol.
If the service requests are in the clear (http), then you might want to consider a secure (https) logon transaction, which gains you a limited-time token to authorise future requests (a session cookie, in effect). Then at least eavesdroppers don't get credentials that work forever, just for a limited period.
Likewise even if the logon transaction isn't secure, at least if it only happens once it's slightly harder to eavesdrop. It's also slightly harder to use.
If you don't care about security, I wouldn't even use a username/password, just an API key. Amounts to the same thing, but if the user doesn't choose it then at least it won't be similar to any of their other passwords, so it doesn't affect anything else when it's stolen.
If you care about security sufficiently that everything is done over https, then it doesn't really make a lot of difference what identification mechanism you use, AFAIK. So do something simple.
Finally, you might care about the security of the authentication, but not about the secrecy of the requests themselves. So, you don't mind eavesdroppers seeing the data in flight, you just don't want them to be able to issue requests of their own (or spoof responses). In that case, you could sign the requests (and responses) using a public/private keypair or a shared secret with HMAC. That might (or might not) be easier to set up and lower bandwidth than SSL. Beware replay attacks.
By optimal are you thinking about performance ? I would suggest to send credentials and authenticate on each request unless you really find this to be a bottleneck. SSL is not enough at all, it only provides encryption and authentication of the web service. But think about client authentication (a client cert can help here) and authorisation, may be not all users of the web service is not allowed to call all methods and all methods calls needs to be logged for auditing. In this case the user identity needs to presented for each call.
I develop and maintain a SOA based core system web service developed in WCF that authenticates and authorises against .Net based clients using windows identity and uses 2-way certs authentication against Java clients and I have no performance problem.
Steve Jessop clarified things for me:
if the credentials are memorized I should provide a transient authentication cookie after they are received,
but if the credentials are digitally stored then I should only use an API key, because anyone who can access the credential storage wouldn't need to access the 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.