As you can see from this Bugzilla thread (and also), Firefox does not always send an Origin header in POST requests. The RFC states that it should not be sent in certain undefined "privacy-sensitive" contexts. Mozilla defines those contexts here.
I'd like to know whether these are the only situations in which Firefox will not send the Origin header. As far as I can tell, it also will not send it in cross-origin POST requests (though Chrome and Internet Explorer will), but I can't confirm that in the documentation. Is it enumerated somewhere that I'm missing?
The Origin spec indicates that the Origin header may be set to "null". This is typically done when the request is coming from a file on a user's computer rather than from a hosted web page. The spec also states that the Origin may be null if the request comes from a "privacy-sensitive" context.
Setting the Origin header. The browser adds the Origin header to the HTTP request before sending the request to the server. The browser is solely responsible for setting the Origin header. The Origin header is always present on cross-origin requests, and the client has no way of setting or overriding the value.
The reason for that is, as mentioned earlier in this answer, browsers always send the Origin header in all POST , PUT , PATCH , and DELETE requests. Also, for completeness here and to be clear: For navigations, browsers send no Origin header.
The Origin request header indicates the origin (scheme, hostname, and port) that caused the request. For example, if a user agent needs to request resources included in a page, or fetched by scripts that it executes, then the origin of the page may be included in the request.
That is, if a user navigates directly to a resource — by pasting a URL into a browser address bar, or by following a link from another web document — then browsers send no Origin header. * The algorithm in the Fetch spec that requires browsers to send the Origin header for all CORS requests is this:
The Origin header in a HTTP request indicates where the request originated from. This can be useful in preventing cross-site request forgery. Sjoerd Langkemper Web application security Prevent CSRF with the Origin request header Feb 27, 2019 The Origin header in a HTTP request indicates where the request originated from.
I've finally figured out an answer to this. There is at least one other situation where an Origin header may be "null". When following a redirect during a CORS request, if the request is redirected to a URL on a different server, the Origin header will be changed to "null".
Issuing the request with a "null" Origin allows those use cases, but prevents the exploitation of trust that sending along the original Origin header would allow. Show activity on this post.
As far as what the relevant specs actually require, the answer has a couple parts:
null
Here are the details:
null
The HTML spec uses the term opaque origin and defines it as an “internal value”:
with no serialization it can be recreated from (it is serialized as "null" per ASCII serialization of an origin), for which the only meaningful operation is testing for equality
In other words everywhere the HTML spec says opaque origin, you can translate that to null
.
The HTML spec requires browsers to set an opaque origin or unique origin in these cases:
img
elements)video
and audio
elements)data:
URLiframe
with a sandbox
attribute that doesn’t contain the value allow-same-origin
createDocument()
, etc.The Fetch spec requires browsers to set the origin to a “globally unique identifier” (which basically means the same thing as “opaque origin” which basically means null
…) in one case:
The URL spec requires browsers to set an opaque origin in the following cases:
blob:
URLsfile:
URLshttp
, https
, ftp
, ws
, wss
, or gopher
.But note that just because the browser has internally set an opaque origin—essentially null
—that doesn’t necessarily mean the browser will send an Origin
header. So see the next part of this answer for details about when browsers must send the Origin
header.
Browsers send the Origin
header for cross-origin requests initiated by a fetch()
or XHR call, or by an ajax method from a JavaScript library (axios, jQuery, etc.) — but not for normal page navigations (that is, when you open a web page directly in a browser), and not (normally) for resources embedded in a web page (for example, not for CSS stylesheets, scripts, or images).
But that description is a simplification. There are cases other than cross-origin XHR/fetch/ajax calls when browsers send the Origin
header, and cases when browsers send the Origin
header for embedded resources. So what follows below is the longer answer.
In terms of the spec requirements: The spec requires the Origin
header to be sent only for any request which the Fetch spec defines as a CORS request:
A CORS request is an HTTP request that includes an
Origin
header. It cannot be reliably identified as participating in the CORS protocol as theOrigin
header is also included for all requests whose method is neitherGET
norHEAD
.
So, what the spec means there is: The Origin
header is sent in all cross-origin requests, but it’s also always sent for all POST
, PUT
, PATCH
, and DELETE
requests — even for same-origin POST
, PUT
, PATCH
, and DELETE
requests (which by definition in Fetch are actually “CORS requests” — even though they’re same-origin).*
The other cases when browsers must send the Origin
header are any cases where a request is made with the “CORS flag” set — which, as far as HTTP(S) requests, is except when the request mode is navigate
, websocket
, same-origin
, or no-cors
.
XHR always sets the mode to cors
. But with the Fetch API, those request modes are the ones you can set with the mode
field of the init-object argument to the fetch(…)
method:
fetch("http://example.com", { mode: 'no-cors' }) // no Origin will be sent
Font requests always have the mode set to cors
and so always have the Origin
header.
And for any element with a crossorigin
attribute (aka “CORS setting attribute”), the HTML spec requires browsers to set the request mode to cors
(and to send the Origin
header).
Otherwise, for embedded resources — any elements having attributes with URLs that initiate requests (<script src>
, stylesheets, images, media elements) — the mode for the requests defaults to no-cors
; and since those requests are GET
requests, that means, per-spec, browsers send no Origin
header for them.
When HTML form elements initiate POST
requests, the mode for those POST
s also defaults to no-cors
— in the same way that embedded resources have their mode defaulted to no-cors
. However, unlike the no-cors
mode GET
requests for embedded resources, browsers do send the Origin
header for those no-cors
mode POST
s initiated from HTML form elements.
The reason for that is, as mentioned earlier in this answer, browsers always send the Origin
header in all POST
, PUT
, PATCH
, and DELETE
requests.
Also, for completeness here and to be clear: For navigations, browsers send no Origin
header. That is, if a user navigates directly to a resource — by pasting a URL into a browser address bar, or by following a link from another web document — then browsers send no Origin
header.
* The algorithm in the Fetch spec that requires browsers to send the Origin
header for all CORS requests is this:
To append a request Origin
header, given a request request, run these steps:
1. Let serializedOrigin be the result of byte-serializing a request origin with request.
2. If request’s response tainting is "cors
" or request’s mode is "websocket
", then
append Origin
/serializedOrigin to request’s header list.
3. Otherwise, if request’s method is neither GET
nor HEAD
,
then: [also send the Origin
header in that case too]
Step 2 there is what requires the Origin
header to be sent in all cross-origin requests — because all cross-origin requests have their response tainting set to "cors
".
But step 3 there requires the Origin
header to also be sent for same-origin POST
, PUT
, PATCH
, and DELETE
requests (which by definition in Fetch are actually “CORS requests” — even though they’re same-origin).
The above describes how the Fetch spec currently defines the requirements, due to a change that was made to the spec on 2016-12-09. Up until then the requirements were different:
• previously no Origin
was sent for a same-origin POST
• previously no Origin
was sent for cross-origin POST from a <form>
(without CORS)
So the Firefox behavior the question describes is what the spec previously required, not what it currently requires.
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