Safari由于浏览器设置标头而拒绝重定向的CORS请求 [英] Safari rejects redirected CORS request due to browser-set headers
问题描述
摘要
Safari拒绝一些涉及重定向的CORS请求,声称不允许某些标题。
- Safari的行为是一个
- 是否有问题,或
- 有什么原因吗?
错误表示CORS中不允许有某个标题
我观察到Safari出现的情况比其他浏览器更严格地解释CORS协议。 [错误] 无法加载资源:请求头字段... ...不允许由访问控制允许标头
。
看到这个头字段 Accept-Encoding
,并将该字段添加到 Access-Control-Allow-Headers
使用 DNT
重复相同的错误。预检请求的 Access-Control-Request-Headers
列表中包含的其他字段为 Cache-Control
,原始
和接受语言
。
告诉,这只影响被重定向的请求。
WHATWG XHR:请求应该没有作者集标题
我在自己的代码中创建了 XMLHttpRequest
,没有任何库或框架干扰它。我绝对肯定我从未呼叫过
WHATWG XHR规范因此,我假设我的作者请求标头列表应为空。 请求部分说明:
作者请求标头最初为空< a href =https://fetch.spec.whatwg.org/#concept-header-list =nofollow>标头列表。
我可以在文档中读到 send()
可能会触发作为作者请求标头的 Content-Type
,即使使用这样的无参数调用也会遇到问题。
W3C CORS:只有作者集标题有用
W3C CORS推荐说明了 Access-Control-Request-Headers
字段由作者请求标头组成:
如果作者请求标头不为空时包含
访问控制请求标头
头作为标头字段值以逗号分隔的头字段名称列表作者请求标头,每个转换为ASCII小写(即使一个或多个是 simple header )。
根据该规范,我可以看到错误的原因是:
如果作者请求标头不是 ASCII不区分大小写匹配其中一个标题字段名称在 标头中,并且标题不是简单标题,应用缓存和网络错误步骤。
WHATWG Fetch从XHR获取列表
也许W3C CORS的建议是错误的地方看。也许它已被 WHATWG Fetch生活标准取代?在其中有关 CORS-预检取的部分写道
- 是 li>
让 headers 为 的请求的标题列表 headers ,不包括 CORS安全列表请求 - 标题和重复项,按字典顺序排序,以及字节小写。 p>
设置 < a href =https://fetch.spec.whatwg.org/#http-access-control-request-headers =nofollow>
访问控制请求标头$ c -listrel =nofollow>标题列表。
那么这里的标题列表是什么? XHR 和抓取似乎是 send()
方法规范。
让 req 成为新的请求,初始化如下:
所以它绑定作者请求头(根据我上面的考虑应该是空的)到头列表,用于构建请求的头的列表。至少最初。
标题可能会被添加
当然,Fetch规范很长,在许多 地方中的头部列表。很可能有一些子句在某处,其中强制添加某些头字段。但我看不到
Accept-Encoding
或DNT
被明确地提到作为预期添加的部分。它们列为禁止标题,作者不应该对其进行控制。
但是,下面的 HTTP-network-or-cache fetch section in a note:
修改 httpRequest 的
注意:如果我们可以使用这更规范不知何故。此时标头,例如
接受编码
,连接
,DNT
和主机
,必要时附加。
接受
,Accept-Charset
,Accept-Language
。
注意:
已经包含接受
和Accept-Language
(除非fetch使用
,默认情况下不包括后者),Accept-Charset
是浪费字节。有关详情,请参见 HTTP标头层分区。 / p>
我觉得很难判断此添加的范围。这是添加头每个HTTP的额外的头被考虑为CORS的原因,除了auther指定的?但是为什么只有在重定向的情况下? HTTP重定向抓取部分未提及向其中添加任何更多标题请求标头列表。
观察到的行为会很糟糕
如果我观察到的行为是根据spec,那么我的主要关注是它将基本上阻止添加新的和有用的HTTP头。你永远不会知道哪些网站可能突然崩溃,因为浏览器开始不仅添加它们,而且将它们包括在CORS检查。另一方面,只考虑作者创建的脚本,将请求创建库与服务器实现匹配就足够了,不用担心什么浏览器会做。
问题
所以我重复我的主要问题:
- Safari的行为是一个错误,
- 规格有问题,或
- 是否有这样的原因?
解决方法
对于一个服务器,我只是通过配置我的Apache 来解决这个问题,以返回所有头,但这是一个解决方法。我想真正了解Safari在这里做什么,以及为什么。
交叉链接
SO的几个问题表明Safari在CORS和重定向的组合中存在问题:
Safari Ajax cors请求不遵循重定向(2013)
接受的答案指出Apple声称这是HTML规范的写法没有引用来源。听起来像 Webkit错误112471评论2 ,但答案早于评论。 / p>
HTML5 CORS请求在重定向后在Safari Safari中失败 2014)
接受的自我答案提出了服务器辅助的解决方法。
Safari在302重定向(2015)后失败CORS请求
未接受的回答提及webkit 错误98838 (未确认),反过来建议错误112471 (最近修复)。那一个在某些时候还提到错误63460 题为CORS应该只处理请求标题设置的脚本作者,但似乎没有达到一个明确的共识。最后,DNT
标志被明确命名。
在302重定向(2015)后,Safari将简单Cors请求变为Preflight
未应答。
右侧类似问题的列表可能提供更多信息。
解决方案
- WHATWG Fetch确实删除了CORS(它定义了CORS内联)。 li>
- CORS只注意在网络级别之前设置的标头(基本上只有在API级别设置的标头)。其中一些可以由浏览器设置,例如
Accept
,但我不能想到会影响CORS的。
所以,我认为Safari有一个bug,但他们最近在这一领域进行了更改,因此WebKit nightlies或Safari技术预览可能做得更好。
Summary
Safari rejects some CORS requests which involve redirects, claiming that some header is not allowed. But that header is never requested by the script, but added by the browser, so I think it should not matter.
- Is Safari's behavior a bug,
- is there a problem with the specs, or
- is there a reason for things to be like this?
Error indicates some header is not allowed in CORS
I'm observing situations where Safari appears to interpret the CORS protocol more strictly than other browsers. It rejects certain requests with the error message
[Error] Failed to load resource: Request header field … is not allowed by
Access-Control-Allow-Headers
.I've seen this for the header field
Accept-Encoding
, and after adding that field toAccess-Control-Allow-Headers
the same error was repeated withDNT
. Other fields included in theAccess-Control-Request-Headers
list of the preflight request areCache-Control
,Origin
andAccept-Language
.As far as I can tell, this only affects requests which get redirected. In cases where I managed to immediately name the final location, the request succeeded.
WHATWG XHR: Request should have no author-set headers
I created the
XMLHttpRequest
in my own code, without any library or framework interfering with it. I'm absolutely certain I never called thesetRequestHeader()
method.Following the WHATWG XHR spec I would therefore assume that my author request headers list should be empty. The Request section states:
The author request headers is an initially empty header list.
I can read in the documentation that a non-empty argument to
send()
might triggerContent-Type
as an author request header, but I'm experiencing problems even with such a no-argument call.W3C CORS: Only author-set headers should matter
The W3C CORS recommendation describes the
Access-Control-Request-Headers
field as being composed of author request headers:If author request headers is not empty include an
Access-Control-Request-Headers
header with as header field value a comma-separated list of the header field names from author request headers in lexicographical order, each converted to ASCII lowercase (even when one or more are a simple header).And the likely reason for an error that I can see, according to that spec, would be this:
If the field name of each header in author request headers is not an ASCII case-insensitive match for one of the header field names in headers and the header is not a simple header, apply the cache and network error steps.
WHATWG Fetch takes the list from XHR
Perhaps the W3C CORS recommendation is the wrong place to look. Perhaps it has been superseded by the WHATWG Fetch living standard? That writes in its section about CORS-preflight fetch
Let headers be the names of request's header list's headers, excluding CORS-safelisted request-headers and duplicates, sorted lexicographically, and byte-lowercased.
Let value be the items in headers separated from each other by 0x2C.
Set
Access-Control-Request-Headers
to value in preflight's header list.
So what is the header list here? The connection between the living standards for XHR and Fetch appears to be the
send()
method specification.
Let req be a new request, initialized as follows:
So it binds the author request headers (which according to my considerations above should be empty) to the header list which is used to build the list of requested headers. At least initially.
Headers might get added
Of course, the Fetch specification is long, and mentions the term "header list" in many places. It might well be that there is some clause somewhere in there which mandates adding certain header fields. But I see no portion where
Accept-Encoding
orDNT
are explicitely mentioned as intended additions. They are listed as forbidden headers over which an author should have no control.However, the following bit of text from the HTTP-network-or-cache fetch section mentions them in a note:
Modify httpRequest's header list per HTTP.
Note: It would be great if we could make this more normative somehow. At this point headers such as
Accept-Encoding
,Connection
,DNT
, andHost
, are to be appended if necessary.
Accept
,Accept-Charset
, andAccept-Language
must not be included at this point.Note:
Accept
andAccept-Language
are already included (unlessfetch()
is used, which does not include the latter by default), andAccept-Charset
is a waste of bytes. See HTTP header layer division for more details.
I find it very hard to judge the scope of this addition. Is this "adding headers per HTTP" the cause for extra headers being considered for CORS, in addition to those specified by the auther? But why only in case of redirects? The HTTP-redirect fetch section does not mention adding any more headers to the list of request headers.
Observed behavior would be bad
If the behavior I observe were according to the spec, then my main concern would be that the it would essentially prevent the addition of new and useful HTTP headers. You'd never know which sites might suddenly get broken as browsers start to not only add them but also include them in CORS checks. On the other hand, with only author-created scripts being considered, it would be sufficient to match request creation library to server implementation, with no worries about what browsers do. Sounds like a much saner setup to me.
Question
So I repeat my main question:
- Is Safari's behavior a bug,
- is there a problem with the specs, or
- is there a reason for things to be like this?
Workaround
For one server I just solved this by configuring my Apache to return all headers, but that's more of a workaround. I'd like to really understand what Safari is doing here, and why.
Cross links
There are several questions on SO indicating that Safari has problems with the combination of CORS and redirects:
Safari Ajax cors request not following redirect (2013)
Accepted answer states that "Apple claims that this is the way the HTML spec is written" without citing a source. Sounds like Webkit bug 112471 comment 2 except that answer predates the comment.HTML5 CORS request fails in safari after redirect (2014)
Accepted self-answer proposes a server-assisted workaround.Safari fails CORS request after 302 redirect (2015)
Unaccepted answer mentions webkit bug 98838 (unconfirmed) which in turn suggests bug 112471 (recently fixed). That one at some point also mentions bug 63460 titled "CORS should only deal with request headers set by script authors", but doesn't seem to reach a definite consensus on this. Towards the end theDNT
flag is explicitely named.Safari turns Simple Cors Request into Preflight after 302 redirect (2015)
Unanswered.The list of similar questions on the right might provide further information.
解决方案It might help if you split up your questions next time.
- WHATWG Fetch indeed obsoletes CORS (it defines CORS inline).
- CORS only pays attention to headers set before the network level (basically only those set at the API level). Some of these could be set by the browser, e.g.,
Accept
, but I can't think of one that would affect CORS.So yeah, I think Safari has a bug, but they have been making changes in this area very recently, so WebKit nightlies or Safari Technology Preview might do better.
这篇关于Safari由于浏览器设置标头而拒绝重定向的CORS请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!