I have a site with mixed HTTP / HTTPS. When the user logs in, she gets two cookies:
a regular cookie with her (signed) username, login expire time, and an "insecure" flag
a secure cookie with her (signed) username, login expire time, and a "secure" flag
note that if you don't have the secure/insecure flag within the signed content, an attacker can intercept the regular cookie and then send it as the secure one (my first implementation made this mistake)
I use the regular cookie on HTTP pages (just for showing her name while she browses the marketing portion of the site). Then I use the secure cookie when she's on HTTPS pages (any user-specific pages).
I got the idea from Secure cookies and mixed https/http site usage.
Everything works great, except that when the user navigates from an HTTPS page to an HTTP one, all of the secure cookies get deleted - which means that they can't go back to HTTPS pages after visiting even a single HTTP page. I should mention that there is a "301 Moved Permanently" that redirects the user to from HTTPS to HTTP.
My site isn't clearing the secure cookie. I know that the browser shouldn't send me the secure cookie while the user is looking at an HTTP site, but I expected the cookie to stick around for its lifetime, and get sent if the user ends up on an HTTPS page again.
I'm getting this same behavior on Chrome, Firefox, and IE. Any tips? I hope this isn't the expected behavior...
Welp, that's embarassing. Here's what my problem turned out to be.
When the user tried to visit an HTTPS site from an HTTP one, their request would start as HTTP
I would check their login credentials (which would fail, because the secure cookie wasn't there), then redirect them to HTTPS. My "require login" and "require HTTPS" systems were separate (a bad design now, but it was convenient in the bad old days where the login cookie wasn't secure)
I thought my secure cookie was being deleted because the Chrome cookie browser doesn't show secure cookies when the page being shown is HTTP. The cookies were there all along.
Related
I have an http-https redirect configuration set up in NGINX:
server {
listen 80;
server_name localhost;
return 301 https://$server_name$request_uri;
}
My question is: Is there at any point, from the user initially accessing the login page of my application to POSTing his username+password, a time when the credentials are going clear over HTTP before being redirected to HTTPS?
It depends on your login form somewhat (it should always post to the https url only), but based on this info, I think no, the password always goes over https when used as intended.
However, you might want to note a few things and add more protection (defense in depth), because the whole point in attacks is to make things not go as intended. :)
SSL Stripping
An attacker might be able to degrade the connection to http from the user's perspective while the attacker himself maintains a secure connection with the server. Note that this would work even if the server does not even respond on plain http. See this video or this link (among many others). The solution is HSTS (see below).
Attacker injecting plain http request
If the attacker can inject a plain http request in any way into the client browser that sends the credentials over plain http, those credentials will not be protected. This applies to username/password being posted, but also to the session cookie, which is equivalent to user credentials for the duration of the session. So this means if the attacker can for example insert an image with src="http://yoursite.com", the session cookie will be sent plaintext. The response will be a redirect as per your nginx settings, but that's too late. Always setting your session cookie as secure solves this problem (but not the other one about posting the credentials, which can be mitigated by HSTS).
HSTS
Your website should have a Strict-Transport-Security response header, so that once a browser had a chance to talk to the server without a man-in-the-middle attacker removing the header, it will remember to use https even if the user does not explicitly specify it in the url bar.
Strict-Transport-Security: max-age=31536000; includeSubDomains
More info on HSTS is here.
If all our sites are secure (HTTPS), is setting the secure flag on cookies redundant?
Are there any pros or cons of setting / not setting the secure if we only have secure sites in our setup?
No, it is not redundant.
Consider the following scenarios.
Situation normal:
User --> Your Website (example.com)
Man-In-The-Middle situation:
User --> MITM --> Your Website (example.com)
If your website listens on port 80 for plain HTTP, and port 443 for HTTPS, then the MITM would have to pass the HTTPS traffic from the User to Your Website as pure TCP data, otherwise the User would get a certificate warning due to the fact the attacker does not have the private key for the example.com SSL/TLS cerfificate.
However, they can still intercept plain HTTP traffic on port 80. Therefore if example.com sets the cookie
AuthenticationSession=0d8d7050f48dc858975c48d32796cd2e5bad2d18
without the Secure flag, the attacker can still intercept this on port 80.
If your website does not listen on port 80 the situation is as follows.
User -tcp80--> MITM
User -tcp443-> MITM -tcp443-> Your Website (example.com)
So, although there is nothing listening at your end on port 80, the attacker could inject the following
<img src="http://example.com/foo.jpg" />
into another request the User makes:
User -tcp80--> MITM --> example.org
Which causes the following to happen:
User -tcp80--> MITM intercepting example.com
sending the cookie to the attacker for example.com
Note that http://example.com:443 will also cause the cookie data to be sent before the server realises it has not gotten an HTTPS handshake, exposing the cookie in the clear:
User --plain HTTP over tcp443--> example.com
In this situation the attacker does not have to be a Man-In-The-Middle, they could just be passively observing the connection to example.com.
Once the attacker grabs the main authentication cookie for a site, they can effectively hijack the User's session and be logged in as them.
If you want to make the Secure flag redundant, implement an HSTS policy. This informs the browser never to connect to Your Website over plain HTTP until the max-age has expired (say 180 days).
Therefore any attacker trying to inject a plain HTTP URL in an image tag will have this changed to HTTPS by the browser, and therefore will render unreadable by anything other than the server. This is known as a 307 internal redirect:
This is [the browser] saying
“I’m not even going to issue that request, instead I’m going to change
it to HTTPS then try again”
However, as a defence-in-depth approach and to provide support for older browsers, I would still include the Secure flag.
Cons? You will be sending the number of bytes within the string "; secure" extra, but only when the cookie is set. And if you need to use the cookie over plain HTTP, you cannot.
If all our sites are secure (HTTPS), is setting the secure flag on cookies redundant?
No, it isn't.
The secure flag prevents the cookie from being sent over HTTP.
Even if your server doesn't listen on port 80 at all (and most HTTPS sites also have an HTTP site that redirects to the HTTPS side), clients which try to connect to port 80 can be subject to man-in-the-middle attacks.
Pros
It protects the cookie
Cons
It costs an insignificant number of bytes.
The point of the secure flag is for the browser to never send the cookie over plain http, regardless of whether the application developer intended to send it only over https. Consider an attack where for example in an html editor form, an attacker can insert images. If he adds an image with a http://server source, the cookie will be sent plaintext unless set as secure. Of course there may be countless other ways to try and inject a plain http request.
If the application server only listens on tcp/443, that's more difficult for an attacker (he could still try things like http://server:443 and see how fast the server drops the obviously invalid connection). It's still the best practice to set all cookies as secure.
So it's not only about man in the middle.
I can't get the cookie set in the browser. This happens when I add www to the cookie domain, but can't figure out why.
Problem description
We have a domain mycompany.com, an application running under mycompany.com and another application under subdomain.mycompany.com. Each of them has their own cookie, secure and httpOnly. We don't want this cookies to be shared between domains. We had the domain for the cookie of mycompany.com set as .mycompany.com. The problem with this is that it leaks to subdomain.mycompany.com, so to avoid it I've changed the domain to www.mycompany.com. In our apache config, we redirect all requests for mycompany.com to www.mycompany.com and all traffic is redirected to https.
So when I go to mycompany.com or www.mycompany.com I end up in www.mycompany.com, the domain and the cookie domain match, this should work, but it doesn't. The cookie for mycompany.com is not in the local storage (Chrome and Firefox). (I've also tried using just mycompany.com as the cookie domain, but as expected the cookie leaks to subdomain.mycompany.com as when I used .mycompany.com)
Here is the cookie as sent back by the server:
my_cookie=xxxxxxxxxxxxxx;Version=1;Comment=;Domain=www.mycompany.com;Path=/;Max-Age=604800000;Secure;HttpOnly;Expires=Fri, 26 Aug 2016 09:32:40 GMT
Reading about this, I thought the problem could be the redirection, but this happens regardless of whether I go to mycompamy.com or www.mycompany.com.
What am I doing wrong?
PS: The cookie is not being generated by the application running under mycompany.com, but by another process running under services.mycompany.com, which the client sends the requests to in order to get the cookie. Maybe this could be the problem.
PS: The cookie is not being generated by the application running under
mycompany.com, but by another process running under
services.mycompany.com, which the client sends the requests to in
order to get the cookie. Maybe this could be the problem.
Yes as a security measure, services.mycompany.com would only be able to set cookies for services.mycompany.com or .mycompany.com.
If browsers could set cookies for other domains then this would lead to cookie poisoning attacks (e.g. compromising the Double Submit Cookie CSRF control, allowing Session Fixation or introducing XSS where raw cookie values are reflected in a response).
Even if you do change it so that www.mycompany.com sets a www.mycompany.com cookie, be aware that something-outside-your-control.mycompany.com can set a cookie at .mycompany.com level which your www.mycompany.com domain wouldn't know where it had been set from. This is because in the HTTP request only the name and value is sent for the cookie, not the domain from where it was set.
In typical session riding scenario attacker makes victim machine to send HTTP request to web site they are already logged in, for example tricking victim to open link in the case of CSRF attack. Browser includes the session cookie (and all other cookies for that site) in the HTTP request, thus attacker can execute any - possibly malicious - operation victim is authorized to perform.
HTTPS encrypts the whole packet, thus making it impossible to read the content, including headers and cookies. But does it protect from session riding attacks, or will the browser still include the cookies and use correct encryption automatically?
will the browser still include the cookies and use correct encryption automatically?
Yes. A CSRF attack works because the browser treats the request just like any other the user would normally want to make. Both HTTP and HTTPS requests are sent as usual with all cookie data. That's why it's up to the server side of the application to compensate with tokens.
I have a site which after the initial login pages (in https) should redirect to a http site.
I have noticed the session cookie is not carried over between the https and http requests.
What would be a secure way to do this?
Right now as an interim solution I generate a one time unique key to use the first time I move from https to http. This, after verified, re-creates the user session.
What would be a secure way to do this?
There isn't one. At best you end up sending session tokens in the clear and are open to session hijacking. At worst, you expose the user to a MitM attack (even on the pages that both you and the user think are secure, as long as they got there from a http only page).
Serve the entire site over HTTPS. The overhead isn't that high and it removes so many potential security pitfalls.