浏览器什么时候发送 Origin header?浏览器什么时候将原点设置为空?
When do browsers send the Origin header? When do browsers set the origin to null?
从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可以看出。
我想知道这些是否是 Firefox 不会发送 Origin 的唯一情况 header。据我所知,它也不会在 cross-origin POST 请求中发送(尽管 Chrome 和 Internet Explorer 会),但我无法在文档中确认这一点。是否列举了我遗漏的地方?
就相关规范的实际要求而言,答案分为几个部分:
- 当浏览器必须在内部将原点设置为将被序列化为
null
的值时
- 当浏览器必须发送 Origin 时 header
详情如下:
当浏览器必须将 origin 设置为将被序列化为 null
的值时
HTML 规范使用术语 opaque origin 并将其定义为“内部值”:
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
换句话说,HTML 规范到处都说 不透明来源 ,您可以将其翻译成 null
.
HTML 规范要求浏览器在这些情况下设置不透明来源或唯一来源:
- Cross-origin images (including cross-origin
img
elements)
- Cross-origin media data (including cross-origin
video
and audio
elements)
- Any document generated from a
data:
URL
- Any
iframe
with a sandbox
attribute that doesn’t contain the value allow-same-origin
- Any document programmatically created using
createDocument()
, etc.
- Any document that does not have a creator browsing context
- Responses that are network errors
- 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
在一种情况下,Fetch 规范要求浏览器将来源设置为“全球唯一标识符”(这基本上与“不透明来源”的意思相同,基本上意味着 null
…):
URL 规范要求浏览器在以下情况下设置不透明来源:
- For
blob:
URLs
- For
file:
URLs
- For any other URLs whose scheme is not one of
http
, https
, ftp
, ws
, wss
, or gopher
.
但请注意,仅仅因为浏览器在内部设置了一个不透明的来源——本质上是 null
——并不一定意味着浏览器会发送 Origin
header。因此,请参阅此答案的下一部分,了解有关浏览器何时必须发送 Origin
header.
的详细信息
当浏览器必须发送 Origin 时 header
浏览器发送 Origin
header 用于 cross-origin 由 fetch()
或 XHR 调用发起的请求,或通过 ajax 方法发起的 JavaScript 库(axios、jQuery 等)——但不适用于正常的页面导航(即,当您直接在浏览器中打开网页时),并且(通常)不适用于网络中嵌入的资源页面(例如,不适用于 CSS 样式表、脚本或图像)。
但该描述是一种简化。当浏览器发送 Origin
header 时,除了 cross-origin XHR/fetch/ajax 调用之外,还有浏览器发送 Origin
header 嵌入资源的情况.所以下面是更长的答案。
根据规范要求:规范要求 Origin
header 仅针对 Fetch 规范定义为 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
.
所以,规范的意思是:Origin
header 在所有 cross-origin 请求中发送, 但 它也总是针对所有 POST
、PUT
、PATCH
和 DELETE
请求发送 — 甚至 same-origin POST
、PUT
、PATCH
和 DELETE
请求(根据 Fetch 中的定义,实际上是“CORS 请求”——尽管它们是 same-origin)。*
浏览器必须发送 Origin
header 的其他情况是在发出请求时设置了“CORS 标志”——就 HTTP(S) 请求而言,是 except when the request mode is navigate
, websocket
, same-origin
, or no-cors
.
XHR 总是 将模式设置为 cors
。但是对于 Fetch API,这些请求模式是您可以使用 fetch(…)
方法的 init-object 参数的 mode
字段设置的模式:
fetch("http://example.com", { mode: 'no-cors' }) // no Origin will be sent
字体请求始终将模式设置为 cors
,因此始终将 Origin
header.
并且对于具有 a crossorigin
attribute 的任何元素(aka “CORS 设置属性”),HTML 规范要求浏览器将请求模式设置为 cors
(并发送 Origin
header)。
否则,对于嵌入式资源——任何具有 URL 属性的元素都会发起请求(<script src>
、样式表、图像、媒体元素)——请求的模式默认为 no-cors
;由于这些请求是 GET
请求,这意味着 per-spec,浏览器不会为它们发送 Origin
header。
当 HTML 表单元素发起 POST
请求时,那些 POST
的模式也默认为 no-cors
— 与嵌入资源有其模式的方式相同默认为 no-cors
。但是,与 no-cors
模式 GET
对嵌入式资源的请求不同,浏览器确实会为那些从 no-cors
模式 POST
发起的请求发送 Origin
header HTML 表单元素。
原因是,如本回答前面所述,浏览器总是发送 Origin
header 总共 POST
、PUT
、PATCH
,以及 DELETE
个请求。
此外,为了这里的完整性和明确性:对于导航,浏览器不发送 Origin
header。也就是说,如果用户直接导航到资源——通过将 URL 粘贴到浏览器地址栏,或者通过跟随来自另一个网络文档的 link——那么浏览器不会发送 Origin
header.
*要求浏览器对所有CORS请求发送Origin
header的algorithm in the Fetch spec是这样的:
追加请求Origin
header,给定一个请求请求,运行这些步骤:
1.设 serializedOrigin 为 byte-serializing 请求来源 request.
的结果
2。如果request的响应污染是“cors
”或者request的模式是“websocket
”,那么
将 Origin
/serializedOrigin 附加到 request 的 header 列表。
3。否则,如果request的方法既不是GET
也不是HEAD
,
然后:[在那种情况下也发送 Origin
header]
第 2 步需要在所有 cross-origin 请求中发送 Origin
header — 因为所有 cross-origin 请求都有其响应污染设置为“cors
”。
但是第 3 步要求 Origin
header 也被发送给 same-origin POST
、PUT
、PATCH
和 DELETE
请求(根据 Fetch 中的定义,它们实际上是“CORS 请求”——尽管它们是 same-origin)。
由于 change that was made to the spec on 2016-12-09,上面描述了 Fetch 规范当前如何定义要求。在那之前,要求是不同的:
• 之前没有为 same-origin POST
发送 Origin
• 之前没有从 <form>
(没有 CORS)
为 cross-origin POST 发送 Origin
因此问题描述的 Firefox 行为是规范以前 所要求的,而不是当前 所要求的。
对我来说,这是在本地主机上以超标准形式 POST 发生在亲戚 URL 上的,并且似乎是由
触发的
<meta name="referrer" content="no-referrer">
在 <head>
.
改成
<meta name="referrer" content="same-origin">
似乎让 Firefox 更快乐。
从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可以看出。
我想知道这些是否是 Firefox 不会发送 Origin 的唯一情况 header。据我所知,它也不会在 cross-origin POST 请求中发送(尽管 Chrome 和 Internet Explorer 会),但我无法在文档中确认这一点。是否列举了我遗漏的地方?
就相关规范的实际要求而言,答案分为几个部分:
- 当浏览器必须在内部将原点设置为将被序列化为
null
的值时
- 当浏览器必须发送 Origin 时 header
详情如下:
当浏览器必须将 origin 设置为将被序列化为 null
的值时
HTML 规范使用术语 opaque origin 并将其定义为“内部值”:
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
换句话说,HTML 规范到处都说 不透明来源 ,您可以将其翻译成 null
.
HTML 规范要求浏览器在这些情况下设置不透明来源或唯一来源:
- Cross-origin images (including cross-origin
img
elements) - Cross-origin media data (including cross-origin
video
andaudio
elements) - Any document generated from a
data:
URL - Any
iframe
with asandbox
attribute that doesn’t contain the valueallow-same-origin
- Any document programmatically created using
createDocument()
, etc. - Any document that does not have a creator browsing context
- Responses that are network errors
- 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
在一种情况下,Fetch 规范要求浏览器将来源设置为“全球唯一标识符”(这基本上与“不透明来源”的意思相同,基本上意味着 null
…):
URL 规范要求浏览器在以下情况下设置不透明来源:
- For
blob:
URLs - For
file:
URLs - For any other URLs whose scheme is not one of
http
,https
,ftp
,ws
,wss
, orgopher
.
但请注意,仅仅因为浏览器在内部设置了一个不透明的来源——本质上是 null
——并不一定意味着浏览器会发送 Origin
header。因此,请参阅此答案的下一部分,了解有关浏览器何时必须发送 Origin
header.
当浏览器必须发送 Origin 时 header
浏览器发送 Origin
header 用于 cross-origin 由 fetch()
或 XHR 调用发起的请求,或通过 ajax 方法发起的 JavaScript 库(axios、jQuery 等)——但不适用于正常的页面导航(即,当您直接在浏览器中打开网页时),并且(通常)不适用于网络中嵌入的资源页面(例如,不适用于 CSS 样式表、脚本或图像)。
但该描述是一种简化。当浏览器发送 Origin
header 时,除了 cross-origin XHR/fetch/ajax 调用之外,还有浏览器发送 Origin
header 嵌入资源的情况.所以下面是更长的答案。
根据规范要求:规范要求 Origin
header 仅针对 Fetch 规范定义为 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
.
所以,规范的意思是:Origin
header 在所有 cross-origin 请求中发送, 但 它也总是针对所有 POST
、PUT
、PATCH
和 DELETE
请求发送 — 甚至 same-origin POST
、PUT
、PATCH
和 DELETE
请求(根据 Fetch 中的定义,实际上是“CORS 请求”——尽管它们是 same-origin)。*
浏览器必须发送 Origin
header 的其他情况是在发出请求时设置了“CORS 标志”——就 HTTP(S) 请求而言,是 except when the request mode is navigate
, websocket
, same-origin
, or no-cors
.
XHR 总是 将模式设置为 cors
。但是对于 Fetch API,这些请求模式是您可以使用 fetch(…)
方法的 init-object 参数的 mode
字段设置的模式:
fetch("http://example.com", { mode: 'no-cors' }) // no Origin will be sent
字体请求始终将模式设置为 cors
,因此始终将 Origin
header.
并且对于具有 a crossorigin
attribute 的任何元素(aka “CORS 设置属性”),HTML 规范要求浏览器将请求模式设置为 cors
(并发送 Origin
header)。
否则,对于嵌入式资源——任何具有 URL 属性的元素都会发起请求(<script src>
、样式表、图像、媒体元素)——请求的模式默认为 no-cors
;由于这些请求是 GET
请求,这意味着 per-spec,浏览器不会为它们发送 Origin
header。
当 HTML 表单元素发起 POST
请求时,那些 POST
的模式也默认为 no-cors
— 与嵌入资源有其模式的方式相同默认为 no-cors
。但是,与 no-cors
模式 GET
对嵌入式资源的请求不同,浏览器确实会为那些从 no-cors
模式 POST
发起的请求发送 Origin
header HTML 表单元素。
原因是,如本回答前面所述,浏览器总是发送 Origin
header 总共 POST
、PUT
、PATCH
,以及 DELETE
个请求。
此外,为了这里的完整性和明确性:对于导航,浏览器不发送 Origin
header。也就是说,如果用户直接导航到资源——通过将 URL 粘贴到浏览器地址栏,或者通过跟随来自另一个网络文档的 link——那么浏览器不会发送 Origin
header.
*要求浏览器对所有CORS请求发送Origin
header的algorithm in the Fetch spec是这样的:
追加请求Origin
header,给定一个请求请求,运行这些步骤:
1.设 serializedOrigin 为 byte-serializing 请求来源 request.
的结果
2。如果request的响应污染是“cors
”或者request的模式是“websocket
”,那么
将 Origin
/serializedOrigin 附加到 request 的 header 列表。
3。否则,如果request的方法既不是GET
也不是HEAD
,
然后:[在那种情况下也发送 Origin
header]
第 2 步需要在所有 cross-origin 请求中发送 Origin
header — 因为所有 cross-origin 请求都有其响应污染设置为“cors
”。
但是第 3 步要求 Origin
header 也被发送给 same-origin POST
、PUT
、PATCH
和 DELETE
请求(根据 Fetch 中的定义,它们实际上是“CORS 请求”——尽管它们是 same-origin)。
由于 change that was made to the spec on 2016-12-09,上面描述了 Fetch 规范当前如何定义要求。在那之前,要求是不同的:
• 之前没有为 same-origin POST
发送 Origin
• 之前没有从 <form>
(没有 CORS)
Origin
因此问题描述的 Firefox 行为是规范以前 所要求的,而不是当前 所要求的。
对我来说,这是在本地主机上以超标准形式 POST 发生在亲戚 URL 上的,并且似乎是由
触发的<meta name="referrer" content="no-referrer">
在 <head>
.
改成
<meta name="referrer" content="same-origin">
似乎让 Firefox 更快乐。