Access-Control-Allow-Origin 标头如何工作?

IT技术 javascript cross-domain cors
2020-12-24 22:22:01

显然,我完全误解了它的语义。我想到了这样的事情:

  1. 从客户端下载JavaScript代码MyCode.js http://siteA-起源
  2. MyCode.js 的响应头包含Access-Control-Allow-Origin:http://siteB,我认为这意味着 MyCode.js 被允许对站点 B 进行跨域引用。
  3. 客户端触发 MyCode.js 的一些功能,然后向 发出请求http://siteB,尽管是跨域请求,这应该没问题。

好吧,我错了。它根本不是这样工作的。所以,我已经阅读了跨域资源共享并尝试阅读w3c 推荐中的跨域资源共享

有一件事是肯定的 - 我仍然不明白我应该如何使用这个标题。

我可以完全控制站点 A 和站点 B。如何启用从站点 A 下载的 javascript 代码以使用此标头访问站点 B 上的资源?

聚苯乙烯

我不想使用 JSONP。

6个回答

Access-Control-Allow-Origin是一个CORS(跨源资源共享)标头

当站点 A 尝试从站点 B 获取内容时,站点 B 可以发送Access-Control-Allow-Origin响应标头以告诉浏览器该页面的内容可由某些来源访问。域,加上方案和端口号。)默认情况下,任何其他源无法访问站点 B 的页面使用Access-Control-Allow-Origin标头为特定请求源的跨源访问打开了一扇门。

对于站点 B 想让站点 A 访问的每个资源/页面,站点 B 应该为其页面提供响应标头:

Access-Control-Allow-Origin: http://siteA.com

现代浏览器不会完全阻止跨域请求。如果站点 A 从站点 B 请求页面,浏览器实际上会在网络级别获取请求的页面并检查响应头是否将站点 A 列为允许的请求者域。如果站点 B 未指示站点 A 被允许访问此页面,则浏览器将触发XMLHttpRequest'serror事件并拒绝对请求 JavaScript 代码的响应数据。

非简单请求

网络级别发生的事情可能比上面解释的稍微复杂一些。如果请求是“非简单”请求,浏览器首先发送一个无数据的“预检”OPTIONS 请求,以验证服务器是否会接受该请求。当其中一个(或两者):

  • 使用 GET 或 POST 以外的 HTTP 动词(例如 PUT、DELETE)
  • 使用非简单的请求头;唯一的简单请求标头是:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type(这仅在其值为application/x-www-form-urlencodedmultipart/form-data、 或时才简单text/plain

如果服务器使用与非简单动词和/或非简单标题匹配的适当响应标题(Access-Control-Allow-Headers对于非简单标题,Access-Control-Allow-Methods对于非简单动词)响应 OPTIONS 预检,则浏览器发送实际请求。

假设站点 A 想要发送一个 PUT 请求/somePage,具有非简单Content-Typeapplication/json,浏览器将首先发送一个预检请求:

OPTIONS /somePage HTTP/1.1
Origin: http://siteA.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type

注意Access-Control-Request-MethodAccess-Control-Request-Headers是浏览器自动添加的;您不需要添加它们。此 OPTIONS 预检获得成功的响应标头:

Access-Control-Allow-Origin: http://siteA.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type

发送实际请求时(预检完成后),行为与处理简单请求的方式相同。换句话说,预检成功的非简单请求被视为与简单请求相同(即,服务器仍必须Access-Control-Allow-Origin再次发送以获得实际响应)。

浏览器发送实际请求:

PUT /somePage HTTP/1.1
Origin: http://siteA.com
Content-Type: application/json

{ "myRequestContent": "JSON is so great" }

然后服务器发回一个Access-Control-Allow-Origin,就像发送一个简单的请求一样:

Access-Control-Allow-Origin: http://siteA.com

有关非简单请求的更多信息,请参阅了解 CORS上的XMLHttpRequest

但是 MyCode.js 首先无法访问站点 B!这个标头将如何到达客户端?顺便说一句,为化身中的光生命滑翔机致敬。
2021-02-06 22:22:01
我进行了澄清编辑:浏览器实际上确实在站点 B 上执行网络提取以检查Access-Control-Allow-Origin标题,但如果标题不允许站点 A 拥有它,它可能不会提供对站点 A 上的 JS 代码的响应。(PS 谢谢:) )
2021-02-14 22:22:01
在使用身份验证的情况下,在某些浏览器(FF 和 Chrome AFAIK)Access-Control-Allow-Origin中不接受*因此,在这种情况下,您必须指定Origin标头中的值希望这会帮助某人。
2021-02-16 22:22:01
@Jwan622 一个基本的“为什么? ”这样的问题可能超出了这个特定答案的范围,这只是关于规则和机制。基本上,浏览器允许,坐在计算机前的人,查看来自任何来源的任何资源。它禁止脚本(可以由任何人编写)从与运行脚本的页面的来源不同的来源读取资源。一些相关的问题是程序员.stackexchange.com / q/ 216605同源策略的威胁模型是什么?
2021-03-02 22:22:01
确实,我在 Fiddler 中看不到任何下载记录,除非跨域请求被批准。有趣的...
2021-03-08 22:22:01

Cross-Origin Resource Sharing - CORS(AKA Cross-Domain AJAX request) 是大多数 web 开发者可能会遇到的问题,根据 Same-Origin-Policy,浏览器将客户端 JavaScript 限制在安全沙箱中,通常 JS 无法直接与远程服务器通信来自不同的域。过去开发者创造了许多棘手的方式来实现跨域资源请求,最常用的方式是:

  1. 使用 Flash/Silverlight 或服务器端作为“代理”与远程通信。
  2. 带填充的 JSON ( JSONP )。
  3. 在 iframe 中嵌入远程服务器并通过 fragment 或 window.name 进行通信,请参阅此处

那些棘手的方法或多或少都有一些问题,例如 JSONP 如果开发人员简单地“评估”它可能会导致安全漏洞,以及上面的 #3,虽然它有效,但两个域之间应该建立严格的契约,既不灵活也不优雅恕我直言:)

W3C 引入了跨域资源共享 (CORS) 作为标准解决方案,以提供一种安全、灵活且推荐的标准方法来解决此问题。

机制

从高层次我们可以简单地认为 CORS 是来自域 A 的客户端 AJAX 调用和域 B 上托管的页面之间的契约,典型的跨域请求/响应将是:

DomainA AJAX 请求标头

Host DomainB.com
User-Agent Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
Accept-Language en-us;
Accept-Encoding gzip, deflate
Keep-Alive 115
Origin http://DomainA.com 

DomainB 响应头

Cache-Control private
Content-Type application/json; charset=utf-8
Access-Control-Allow-Origin DomainA.com
Content-Length 87
Proxy-Connection Keep-Alive
Connection Keep-Alive

我在上面标记的蓝色部分是内核事实,“Origin”请求标头“表示跨域请求或预检请求的来源”,“Access-Control-Allow-Origin”响应标头表示此页面允许远程请求来自DomainA(如果值为 * 表示允许来自任何域的远程请求)。

正如我上面提到的,W3 建议浏览器在提交实际跨域 HTTP 请求之前实现“预检请求”,简而言之,它是一个 HTTPOPTIONS请求:

OPTIONS DomainB.com/foo.aspx HTTP/1.1

如果 foo.aspx 支持 OPTIONS HTTP 动词,它可能会返回如下响应:

HTTP/1.1 200 OK
Date: Wed, 01 Mar 2011 15:38:19 GMT
Access-Control-Allow-Origin: http://DomainA.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, HEAD
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Max-Age: 1728000
Connection: Keep-Alive
Content-Type: application/json

仅当响应中包含“Access-Control-Allow-Origin”且值为“*”或包含提交CORS请求的域时,满足此强制条件浏览器才会提交实际的跨域请求,并缓存结果在“预检结果缓存”中。

三年前我写了一篇关于 CORS 的博客:AJAX 跨域 HTTP 请求

外部网络中的域能否与内部网络中的域通信?
2021-02-14 22:22:01
这个答案让我意识到为什么我突然遇到了一个问题,而没有将这个标头用于 POST 和 GET 请求。我不小心直接从磁盘打开了 index.html 文件,因此客户端在 node.js 上访问的 URL 被认为是跨域的,而它只是在 localhost 上运行。通过 URL 访问(通常会这样做)“解决”了我的问题......
2021-02-23 22:22:01

问题有点太老了,无法回答,但我将其发布以供将来参考此问题。

根据这篇Mozilla 开发者网络文章,

当资源从与第一个资源本身服务的域或端口不同的域或端口请求资源时,它会发出跨域 HTTP 请求

在此处输入图片说明

一个HTML页面从供应http://domain-a.com作出了<img>对SRC请求http://domain-b.com/image.jpg
当今网络上的许多页面都加载了来自不同域的CSS 样式表图像脚本等资源(因此它应该很酷)。

同源政策

出于安全原因,浏览器会限制从脚本内发起的跨域 HTTP请求 例如,遵循同源策略 因此,Web应用程序使用只能使HTTP请求自己的域
XMLHttpRequestFetch
XMLHttpRequestFetch

跨域资源共享 (CORS)

为了改进 Web 应用程序,开发人员要求浏览器供应商允许跨域请求。

所述跨来源资源共享(CORS)机制给出web服务器跨域的访问控制,这使安全跨域数据传送。
现代浏览器API 容器中使用CORS - 例如- 来降低跨源 HTTP 请求的风险。XMLHttpRequestFetch

CORS 的工作原理(Access-Control-Allow-Origin标题)

维基百科

CORS 标准描述了新的 HTTP 标头,这些标头为浏览器和服务器提供了一种只有在他们获得许可的情况下才能请求远程 URL 的方法。

尽管服务器可以执行一些验证和授权,但通常浏览器有责任支持这些标头并遵守它们施加的限制。

例子

  1. 浏览器发送OPTIONS带有Origin HTTP标头请求

    此标头的值是为父页面提供服务的域。当一个页面http://www.example.com试图访问 中用户的数据时service.example.com,以下请求标头将被发送到service.example.com

    来源:http : //www.example.com

  2. 服务器 atservice.example.com可能会响应:

    • Access-Control-Allow-Origin其响应中(ACAO) 标头指示允许哪些源站点。
      例如:

      Access-Control-Allow-Origin: http://www.example.com

    • 如果服务器不允许跨域请求,则出现错误页面

    • Access-Control-Allow-Origin带有通配符(ACAO) 标头,允许所有域:

      Access-Control-Allow-Origin: *

当我不想让任何人通过 CORS 访问我的资源时,我应该设置什么值Access-Control-Allow-Origin我的意思是否定Access-Control-Allow-Origin: *
2021-02-06 22:22:01
我你的网络服务器是Apache,然后你可以放入你的http-confightaccess文件
2021-02-09 22:22:01
只是不要设置任何东西,为此目的
2021-02-15 22:22:01
我把访问控制放在哪里
2021-03-02 22:22:01
如何设置没有被允许acees一些东西 Access-Control-Allow-Origin:null
2021-03-05 22:22:01

每当我开始考虑 CORS 时,我对哪个站点托管标头的直觉是不正确的,正如您在问题中所描述的那样。对我来说,思考同源策略的目的是有帮助的。

同源策略的目的是保护您免受 siteA.com 上的恶意 JavaScript 访问您选择仅与 siteB.com 共享的私人信息。如果没有同源策略,由 siteA.com 的作者编写的 JavaScript 可能会使您的浏览器使用您对 siteB.com 的身份验证 cookie 向 siteB.com 发出请求。这样,siteA.com 就可以窃取您与 siteB.com 共享的秘密信息。

有时您需要跨域工作,这就是 CORS 的用武之地。 CORS 放宽了 siteB.com 的同源策略,使用Access-Control-Allow-Origin标头列出其他域 (siteA.com),这些域被信任运行可以与 siteB 交互的 JavaScript。 com。

要了解哪个域应该为 CORS 标头提供服务,请考虑这一点。您访问了恶意网站,其中包含一些尝试向 mybank.com 发出跨域请求的 JavaScript。应该由 mybank.com 而不是恶意网站来决定是否设置 CORS 标头来放宽同源策略,允许来自恶意网站的 JavaScript 与其交互。如果 malicous.com 可以设置它自己的 CORS 标头,允许它自己的 JavaScript 访问 mybank.com,这将完全取消同源策略。

我认为我直觉不好的原因是我在开发网站时的观点。这是我的网站,使用所有的JavaScript,因此它没有做任何恶意的事情,应该由来指定我的JavaScript 可以与哪些其他网站进行交互。实际上我应该考虑哪些其他站点 JavaScript 正在尝试与我的站点交互,我应该使用 CORS 来允许它们吗?

来自 OP - “我认为我直觉不好的原因是我在开发网站时的观点。这是我的网站,使用我所有的 JavaScript,因此它没有做任何恶意的事情,应该由我来指定我的 JavaScript 可以与哪些其他网站进行交互。” - 对于那些第一次这么想的人(就像我一样),还有另一个规则,不是 CORS,为此:CSP(同意安全策略)- 使用 CSP,您可以指定您的网站可以访问/到达的网站/网址。
2021-02-06 22:22:01
鉴于第 2 段,您在第 3 段中是否有站点 A、站点 B 倒退?我可能会误解,但前面的段落似乎暗示它的 siteA 正在运行有问题的 JS?
2021-02-18 22:22:01

使用ReactAxios,将代理链接加入到 URL 并添加标题,如下所示

https://cors-anywhere.herokuapp.com/ + Your API URL

只需添加代理链接即可工作,但它也可能再次引发无访问权限错误。因此最好添加标题,如下所示。

axios.get(`https://cors-anywhere.herokuapp.com/[YOUR_API_URL]`,{headers: {'Access-Control-Allow-Origin': '*'}})
      .then(response => console.log(response:data);
  }

警告:不得用于生产

这只是一个快速解决方案,如果您正在为无法获得响应而苦恼,您可以使用它。但这又不是生产的最佳答案。

得到了几次反对,这完全有道理,我早就应该添加警告了。

请不要这样做。使用代理链接就像将用户 cookie 交给中间人。应该是非法的恕我直言
2021-02-23 22:22:01
这对我很有用!除了使用 *(存在安全问题)之外,我将访问控制限制为我用来学习的确切地址......在我的情况下是' reqres.in/api/register '
2021-02-28 22:22:01