Is HTTP header Referer sent when going to a http page from a https page? - security

After a few tests, I'm starting to reach the conclusion that a browser does not send a Referer HTTP header when one clicks to a http page from a https one.
What security reason is that for? Is is defined somewhere in the standard?

The HTTP RFC states, in section 15.1.3 Encoding Sensitive Information in URI's :
Clients SHOULD NOT include a Referer
header field in a (non-secure) HTTP
request if the referring page was
transferred with a secure protocol.
So, this is expected / standard behaviour.

Actually it's not that straight forward anymore (2014 onwards), according to this w3c document on referrer policy.
The default behaviour is that browsers will not send referrer information when going from HTTPS to HTTP. However, browsers will send referrer when going from HTTPS to HTTPS.
Also, in HTML5, there is a new meta tag named referrer, that looks like this:
<meta name="referrer" content="origin">
New browsers have already implemented this. So whether or not browsers will send referrer, will depend on this meta tag in the near future. If this meta tag is not included in page's HTML, then browsers will use the default behaviour.
Following are the possible values of content attribute of referrer meta tag:
no-referrer: Referrer will not be sent, regardless of HTTP or HTTPS
origin: Only the origin (main) domain will be sent as referrer
origin-when-crossorigin: Same origin will send full referrer URL and cross origin will send only origin URL as referrer
no-referrer-when-downgrade: This is the default behaviour when no referrer meta tag is provided on the page.
unsafe-url: This will always send referrer, regardless of HTTP or HTTPS
Also, there are some legacy attribute values for referrer meta tag. These are no longer recommended, but used in many sites at the moment:
never: same as no-referrer
default: same as no-referrer-when-downgrade
always: same as unsafe-url
I hope this information will be helpful to someone who just found this post after 2014.

Yes, defined in the standard:
Clients SHOULD NOT include a Referer
header field in a (non-secure) HTTP
request if the referring page was
transferred with a secure protocol

Reason: Sometimes SessionIDs are URL encoded. HTTP Pages can have cross site scripting which steals the session from the HTTPS communication. To prevent this, the referrer is not transmitted on the HTTPS to HTTP transition so that the URL encoded sessin ID can't be stolen.

Related

How to detect (and silently drop) cross-origin requests to my server?

Looking at attacks like CSRF, BREACH, a subset of XS-Leaks and probably many more, a cross-origin request is always involved. I'd like to block such non-toplevel-<a> cross-origin requests (from <form>,<img>,<script>,<link>,fetch(),XMLHttpRequest,<a>-within-iframe and others) to my server (a simple express (node.js) application, but a general answer would be nice). By "block" I mean drop silently on the server side, without sending any response.
I've checked out the Origin HTTP header, but it isn't sent with <img> tags.
The Referer header is easy to omit on the attacker's site's side, so to reject all cross-origin requests I'd need to check that "Referer exists and is me", and that doesn't allow fresh GET requests (nor <a> top-level navigations from other sites).
The Cross-Origin-Resource-Policy: same-site response header and its supplementary headers are nice, but they don't help me avoid sending a response which the attacker can time from js / size as a man-in-the-middle - having the browser reject the content is irrelevant.
Is there an HTTP header I'm overlooking, which clearly identifies a cross-origin request?
Perhaps a browser-specific one?
Is there a plan to introduce one in the foreseeable future in either Firefox or Chrome?

How to preserve referrer (Referer HTTP header) across subdomains?

I have a website running on www.example.com that makes GET requests to api.example.com to process a form. When I examine web server logs for api.example.com I see that requests from Safari get the full referer (e.g., www.example.com/page-where-request-originated). But requests from Chrome only get a partial referer (www.example.com).
I need the ability to track the full referring page when the request hits api.example.com. Reviewing the documentation for Referrer-Policy it seems my only option is to set it to unsafe-url. But that seems overkill because I only want the referrer to be sent for subdomains of example.com. Is that possible?
The only option I can find is strict-origin : Send the origin as referrer, but only when the request is no downgrade from https to http.
see: https://wiki.crashtest-security.com/enable-security-headers
Everything else will either omit the referrer completely or send the origin URL without any URL parameters.

"Accept-Language" header missing in http request from the browser

We have come across an issue in production logs where "Accept-Language" is missing in the http request from the browser. Although I am not able to replicate it so I want to understand any valid use case where any specific browser may send a request without "Accept-Language" header.
Even GET / HTTP/1.0 is a valid HTTP request. You can create one from the telnet client if you wish and it will still return a result from the server!
Accept-Language is a header to aid in content negotiation and is optional. The most widely used browsers send the correct headers, but there may be corporate proxies who may be filtering such headers. You should not rely on this header being present.

Why does RFC 6797 forbid sending of the Strict-Transport-Security header over plain HTTP responses?

When reading the spec for HSTS (Strict-Transport-Security), I see an injunction in section 7.2 against sending the header when accessed over http instead of https:
An HSTS Host MUST NOT include the STS header field in HTTP responses
conveyed over non-secure transport.
Why is this? What are the risks if this is violated?
The danger is to the availability of the website itself. If the website is able to respond (either now or in the future) over HTTP but not over HTTPS, it will semi-permanently prevent browsers from accessing the site:
Browser: "I want http://example.com"
ExampleCom: "You should go to the https:// URL now and for the next 3 months!"
Browser: "I want https://example.com"
ExampleCom: [nothing]
By only serving the STS header over HTTPS connections, the site guarantees that at least right now it is not pointing browsers to an inaccessible site. Of course, if the max-age is set to 3 months and the HTTPS site breaks tomorrow, the effect is the same. This is merely an incremental protection.
If your server cannot positively tell from request characteristics whether it is being accessed over HTTP vs. HTTPS, but you believe you have set up your website to only be accessible over HTTPS anyhow (e.g. due to SSL/TLS termination in an nginx proxy), it should be safe to serve the header all the time. But if you want to serve both, e.g. if you wish to serve HTTP->HTTPS redirects from your server, find out how your proxy tells you about the connection and start gating the STS header response on that.
(Thanks to Deirdre Connolly for this explanation!)
Not sure if you have a specific issue you are trying to solve, or are only asking for curiosity sake but this might be better asked on http://security.stackexchange.com
Like you I can't see the threat from the server sending this over HTTP. It doesn't really make sense, but I'm not sure if there is a risk to be honest. Except to say if you can't set up the header properly then perhaps you're not ready to implement HSTS as it can be dangerous if misconfigured!
The far bigger danger is if a browser was to process a HSTS header received over HTTP, which section 8.1 explicitly states it MUST ignore:
If an HTTP response is received over insecure transport, the UA MUST
ignore any present STS header field(s).
The risk here is that a malicious attacker (or an accidentally misconfigured header) could take a HTTP-only website offline (or the HTTP-only parts of a mixed site) if a browser incorrectly processed it. This would effectively cause a DoS for that user(s) until either the header expiries or the site implements HTTPS.
Additionally if a browser did accept this header over HTTP rather than HTTPS, it could be possible for a MITM attacker to expire the header by setting it to a max-age of 0. For example if you have a long HSTS header set on https://www.example.com but attacker was able to publish a max-age=0 header with includeSubDomain over http://example.com, and the browser incorrectly processed that, then it could effectively remove the protection HTTPS gives to your www site.
For these reasons it's very important that clients (i.e. webbrowsers) implement this correctly and ignore the HSTS header if served over HTTP and only process it over HTTPS. This could be another reason the RFC states servers must not send this over HTTP - just in case a browser implements this wrong but, to be honest, if that happens then that browser is putting all HTTP only websites at risk as a MITM attacker could add it as per above.

CORS: Why there aren't a pre-flight request for POST with Content-Type:text/plain

After reading a lot about CORS and pre-flight requests I still don't quite get why there are some exceptions for doing a pre-flight. Why does it matter if the Content-Type is text/plain or application/json?
If I get it right, the value of CORS is to restrict the returned data (It doesn't care if the POST destroyed the database, it only cares that the browser can't read the output of that operation). But if that's true (and probably It's not) why there are pre-flight requests at all? Wouldn't suffice to just check for a header like Access-Control-Allow-Cross-Origin-Request: true in the response?
The best answer so far I found in the: What is the motivation behind the introduction of preflight CORS requests? question, but it's still a bit confusing for me.
Why does it matter if the Content-Type is 'text/plain' or
'application/json'?
The three content types (enctype) supported by a form are as follows:
application/x-www-form-urlencoded
multipart/form-data
text/plain
If a form is received by a handler on the web server, and it is not one of the above content types then it can be assumed that it was an AJAX request that sent the form, and not an HTML <form /> tag.
Therefore, if an existing pre-CORS system is using the content type as a method of ensuring that the request is not cross-site in order to prevent Cross-Site Request Forgery (CSRF), then the authors of the CORS spec did not want to introduce any new security vulnerabilities into existing websites. They did this by insisting such requests initiate a preflight to ensure both the browser and the server are CORS compatible first.
It doesn't care if the POST destroyed the database, it only cares that
the browser can't read the output of that operation
Exactly right. By default browsers obey the Same Origin Policy. CORS relaxes this restriction, allowing another Origin to read responses from it made by AJAX.
why there are pre-flight requests at all?
As said, to ensure that both client and server are CORS compatible and it is not just an HTML form being sent that has always been able to be submitted cross domain.
e.g. this has always worked. A form on example.com POSTing to example.org:
<form method="post" action="//example.org/handler.php" />
Wouldn't suffice to just
check for a header like 'Access-Control-Allow-Cross-Origin-Request:
true' in the response?
Because of the CSRF vector. By checking that the browser can send a preflight, it ensures that the cross-origin request is authorised before the browser will send it (by examining CORS response headers). This enables the browser to protect the current user's session - remember that the attacker here is not the one running the browser, the victim is running the browser in a CSRF attack, therefore a manipulated browser that doesn't properly check CORS headers or spoofs a preflight would be of no advantage for an attacker to run themselves. Similarly, the preflight enables CSRF mitigations such as custom headers to work.
To summerise:
HTML form cross-origin
Can only be sent with certain enctype's
Cannot have custom headers
Browser will just send it without preflight because everything about a <form> submission will be standard (or "simple" as CORS puts it)
If server handler receives a request from such a form it will act upon it
AJAX cross-origin
Only possible via CORS
Early version of some browsers, like IE 8 & 9 could send cross-origin requests, but not with non-standard headers or enctype's
Can have custom headers and enctype's in fully supported browsers
In order to ensure that a cross-origin AJAX request is not spoofing a same-origin AJAX request (remember that cross-origin didn't used to be possible), if the AJAX request is not simple then the browser will send a preflight to ensure this is allowed
If server handler receives a request it will act upon it, but only if it has passed preflight checks because the initial request will be made with the OPTIONS verb and not until the browser agrees that the server is talking CORS will it send the actual GET or POST

Resources