I assume that the default blocking of custom headers in cors requests is to prevent some kind of attack.
Is that assumption correct? If so, what's the attack?
from https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS
In CORS, a preflight request with the OPTIONS method is sent, so that the server can respond whether it is acceptable to send the request with these parameters. The Access-Control-Request-Method header notifies the server as part of a preflight request that when the actual request is sent, it will be sent with a POST request method.
Cross-origin restrictions in browsers are designed to avoid causing servers to permit scripted cross-origin XHR/Fetch requests to do anything by default more than what browsers already allow for image, script, and stylesheet requests made using img
, script
, and link
markup.
When in the HTML markup for a document or application at origin A you put an img
, script
, or link
element that embeds an image, script, or stylesheet from origin B, there’s no way you can set custom headers on the request for that image, script, or stylesheet from origin B.
Therefore, the default browser behavior for scripted cross-origin XHR/Fetch requests is designed to match the same restrictions inherent in img
/script
/link
-initiated requests.
The general principle at work is to not break any assumptions made in existing server-side code that the code won’t receive requests from documents/applications running in a browser that include custom headers or that do anything else somebody can’t do using img
/script
/link
.
That said, there are a few headers — CORS-safelisted request-headers; basically Accept
, Accept-Language
and Content-Language
— that browsers let you control in scripted cross-origin XHR/Fetch requests but that you have no control over for img
/script
/link
-initiated requests. The reasons those headers ended up being the safelisted set aren’t terrifically clear-cut. See https://lists.w3.org/Archives/Public/public-webappsec/2013Aug/thread.html#msg44:
Accept is pretty random due to plugins. Accept-Language and Content-Language I guess we considered safe enough. Not sure there was any particularly strong rationale...
In the end, it looks somewhat arbitrary because it reflects the vagaries of the evolution in the previous 15 years of the Web platform.
…but basically what it came down to is, the choice of that set is in line with the general principle of not adding any additional risk/surprises that would break assumptions in deployed servers.
The purpose of the CORS protocol is to allow servers to opt-in to something less strict than the default behavior. So the specific way they can opt in to less-strict behavior for request headers is, they can choose to send Access-Control-Allow-Headers
and use that to tailor/tune/control exactly what request headers they want to allow in scripted cross-origin XHR/Fetch requests.
But if they don’t opt-in by choosing to send Access-Control-Allow-Headers
, then they can be confident that browsers aren’t going to allow scripted cross-origin XHR/Fetch requests from frontend JavaScript code to do something surprising/unexpected they have not opted-in to.
To be clear: it’s not ”CORS” that’s imposing the default restrictions. Instead those restrictions are part of the default same-origin policy that browsers follow, and as documented in places like https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy and https://en.wikipedia.org/wiki/Same-origin_policy. So CORS is a means for allowing servers to choose when they want to ask browsers to use less-strict restrictions for particular resources.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With