When do browsers send the Origin header? When do browsers set the origin to null?
Asked Answered
D

3

89

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?

Draco answered 15/2, 2017 at 2:23 Comment(1)
That means, in order to prevent attacks (especially CSRF), one has to handle this in the backend (even though they use CORS restrictions, or Same-origin policy), and disable requests with null origin header.Rogue
P
136

As far as what the relevant specs actually require, the answer has a couple parts:

  • When browsers must internally set an origin to a value that gets serialized as null
  • When browsers must send the Origin header

Here are the details:

When browsers must set origin to a value that gets serialized as 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 it to null.

The HTML spec requires browsers to set an opaque origin or unique origin in these cases:

  1. Cross-origin images (including cross-origin img elements)
  2. Cross-origin media data (including cross-origin video and audio elements)
  3. Any document generated from a data: URL
  4. Any iframe with a sandbox attribute that doesn’t contain the value allow-same-origin
  5. Any document programmatically created using createDocument(), etc.
  6. Any document that does not have a creator browsing context
  7. Responses that are network errors
  8. The Should navigation response to navigation request of type from source in target be blocked by Content Security Policy? algorithm returns Blocked when executed on a navigate response

The Fetch spec requires browsers to set the origin to a “globally unique identifier” (essentially the same thing as “opaque origin”, which basically means null…) in one case:

  1. Redirects across origins

The URL spec requires browsers to set an opaque origin in the following cases:

  1. blob: URLs
  2. file: URLs
  3. any other URLs whose scheme is not one of http, 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.


When browsers must send the Origin header

Browsers send the Origin header for WebSocket requests and 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’s a simplification. There are cases other than WebSocket requests and 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 spec requirements: The spec requires the Origin header to always be sent for WebSocket requests and 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 the Origin header is also included for all requests whose method is neither GET nor HEAD.

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 POSTs also defaults to no-cors — in the same way 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 POSTs 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 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 an 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.

Pulverable answered 15/2, 2017 at 7:11 Comment(6)
can you genearlize it a little: Header is always included except when it's not Get/Head request think [Post], and if it's made by JS XHR then mode is CORS and then headers are included as well, however, with fetch you can change mode and headers wont be included. So does that mean img tag which makes get request without using JS (fetch/xhr) won't have headers origin and referrer sentQuake
do you know if there any way that I can set the origin header to null in ajax CORS request without having to create a sandboxed iframe and communicate with it using postMessages - wish to do anonymous requestsJakie
Explaining "8. The Should navigation response to navigation request of type from source in target be blocked by Content Security Policy? algorithm returns Blocked when executed on a navigate response". ||| These are Content-Security-Policy (CSP) blocked navigation responses. The term "navigation responses" refers to the locations a user can navigate to (via <a>, <iframe>, window.location) or submit a form to (via <form>). fetch responses are not considered in this rule.Barela
@sideshowbarker, your answer somehow became the source for an complete overview of when the Origin header has value null. Even MDN docs refer to your answer. I've been looking through the various (outdated) links that you provided, and I wasn't able to find any source for your statements, beside the ones in the question. How did you find, e.g. the case with the Content-Security-Policy?Barela
After some further digging, it seems that the previous specifications provided some more details, or have since been removed. Moreover, it seems your answer conflicts regarding websocket. You mention that Origin header is sent for request modes except navigate, websocket,... . However, from the Fetch spec that you link in the footnote, it says: "If request’s ... mode is "websocket", then append (Origin, serializedOrigin) to request’s header list."Barela
Great Summary! But also reveals the inglorious messy state of web security standards.Kirchhoff
C
5

For me this was happening on a super-standard form POST to a relative URL on localhost, and seems to have been triggered by having

<meta name="referrer" content="no-referrer">

in the <head>.

Changing it to

<meta name="referrer" content="same-origin">

seemed to make Firefox happier.

Crossman answered 14/12, 2021 at 6:4 Comment(4)
Simple and quick, thanksFantan
Thank you, that helped me track it down. In my case, it was the Referrer-Policy no-referrer header that cause the Origin to not be set (and subsequently the request to be denied because of CORS).Hebrides
But this is for the referer header only. Not the origin header with OP is talking about.Spiegleman
@KernelJames That’s the point—you’d think that this only affects the referer, but when set to no-referrer it also causes the browser to send Origin: null.Crossman
B
4

I wanted to add some information to @sideshowbarker's great answer, which has become the most comprehensive source on this topic and is even linked to by MDN. To supplement this answer, I reviewed various specifications and identified some changes that have occurred since the answer was first posted. I also organized the information to make it easier to read. In addition, I used WebArchive references from early 2023 instead of direct links, since the specs may change in the future.

It's important to note that both @sideshowbarker and my answer should be used as guidelines, as implementations, rulesets, and flavors are up to the discretion of browser maintainers.

Use them as guidelines and if you're uncertain, be sure to perform tests.


As @sideshowbarker mentioned, the various specifications define a null Origin header as:

  • opaque origin
  • null origin

With this, we can filter through the specifications to figure out when the Origin header is null:

  • GET or HEAD requests that do not allow Cross-Origin Resource Sharing (CORS) or use Websockets. For all other request modes that use same-origin, navigate or no-cors, the Origin header is omitted. Some Web APIs allow you to specify the mode, such as fetch, while others have default values, such as an <img> requesting an external resource: 1, 2
    • Any embedded HTML element that requests its content via a URL. These elements include <link>, <script>, <img>, <audio>, <video>, <object>, <embed>, and <iframe>. These HTTP GET requests use the no-cors mode by default, unless a crossorigin attribute is set on the HTML element. Note that <canvas>, <math>, and <svg> are not included, as they cannot request data from external resources (e.g. with a src attribute). 1, 2, 3
    • Any GET or HEAD fetch() request where the mode option has the value "navigate", "same-origin", or "no-cors". By default, fetch() uses the cors mode. 1, 2
    • (Sidenote: XMLHttpRequest, unlike fetch does not allow setting a mode and defaults to cors, meaning all XMLHttpRequest's are sent with the Origin header.)4
  • Referrer-Policy set to no-referrer for any requests that does not use a GET or HEAD method and doesn't use cors or websocket.5
  • Responses that are network errors. A 404 or 500 HTTP response status is no network error, since the the request was successfully able to reach the server. Rather invalid protocol, header or where the server fails to send a response. 6
  • Content-Security-Policy (CSP) blocked navigation responses. The term "navigation responses" refers to the locations a user can navigate to (via <a>, <iframe>, window.location) or submit a form to (via <form>). fetch responses are not considered as navigation responses. 7
  • URL schemas:
    • Any embedded inline file created with the data: scheme8
    • The file: scheme may omit the Origin header (Browser dependent) 9
    • In some cases for the blob: scheme 10
    • Any other URL whose scheme is not one of http, https, ftp, ws, wss or gopher 11
  • Some browsing contexts have no Origin. A browsing context is an environment in which a web page or application is displayed, which can be a tab, a window or even only parts of a page, like a frame or an iframe. A creator (referred to as "creator browsing context" in previous HTML spec's), is the browsing context which was responsible for creating another browsing context. There exist two types of creators, the opener browsing context (e.g. clicking a link to another page, the page embedding the link is the opener) and the parent browsing context (e.g. the page embedding an iframe is a parent browsing context). The HTML specification considers the following cases without Origin header:
    • Any <iframe> with a sandbox attribute that doesn't contain the value allow-same-origin12
    • Any document created programmatically using createDocument() or that do not have a creator browsing context. 13, 14

References:

1 The fetch spec says that Origin is included for all requests except GET or HEAD.
2 The fetch spec says that mode with cors or websocket are send with the Origin header, excluding all other modes.
3 Default mode of the Request() constructor used for fetch and embedded HTML elements
4 The XHR spec says that default mode of XMLHttpRequest is set to cors
5 The fetch spec mentions this in Bullet point #3.1.
6 The HTML spec says that a network error should return no navigation params, which include origins. See Bullet point #21 (Not # 19.21)
7 The HTML spec says that a "Blocked" CSP response leads to a network failure. See Bullet point #6.5 which the CSP specs defines as a network error resolving in reference 5.
8 The HTML spec says that data: scheme returns an opaque origin
9 The URL spec says that the reader should decide how to handle the file: scheme but suggest to use an opaque origin
10 The FileAPI spec lists some specific cases when an opaque origin is used
11 The URL spec lists these URL schemes and fallbacks to "opaque origin"
12 The HTML spec specifies to return an "opaque origin" for this iframe case context. See Bullet point #5
13 The HTML spec says that a Document without browsing context has an "opaque origin". Moreover, the HTML spec says that Document's' created with createDocument() have no browsing context

Barela answered 5/5, 2023 at 9:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.