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

mar*_*ark 1050 javascript cross-domain cors

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

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

好吧,我错了.它根本不起作用.所以,我已经阅读了跨源资源共享,并尝试在w3c推荐中阅读跨源资源共享

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

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

PS

我不想使用JSONP.

aps*_*ers 1332

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
Run Code Online (Sandbox Code Playgroud)

现代浏览器不会直接阻止跨域请求.如果站点A从站点B请求页面,则浏览器将实际获取网络级别上的请求页面,并检查响应头是否将站点A列为允许的请求者域.如果站点B没有指出该网站上被允许访问该页面时,浏览器会触发XMLHttpRequesterror事件和响应数据拒绝请求的JavaScript代码.

非简单请求

在网络级别上发生的事情可能比上面解释的稍微复杂一些.如果请求是"非简单"请求,则浏览器首先发送无数据"预检"OPTIONS请求,以验证服务器是否接受请求.任何一个(或两个)请求都是非简单的:

  • 使用除GET或POST之外的HTTP动词(例如PUT,DELETE)
  • 使用非简单的请求标头; 唯一简单的请求标头是:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type(当它的值是,或者application/x-www-form-urlencoded,这只是简单的)multipart/form-datatext/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
Run Code Online (Sandbox Code Playgroud)

请注意,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
Run Code Online (Sandbox Code Playgroud)

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

浏览器发送实际请求:

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

{ "myRequestContent": "JSON is so great" }
Run Code Online (Sandbox Code Playgroud)

并且服务器发回一个Access-Control-Allow-Origin,就像它对一个简单的请求一样:

Access-Control-Allow-Origin: http://siteA.com
Run Code Online (Sandbox Code Playgroud)

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

  • @ Jwan622一个基本的"*为什么?*"这样的问题可能超出了这个特定答案的范围,这只是规则和机制.基本上,浏览器允许*你*,坐在电脑前的人,看到任何来源的任何资源.它不允许脚本(可以由任何人编写)从源自不同于运行脚本的页面的原点的源读取资源.一些相关的问题是http://programmers.stackexchange.com/q/216605/和[同一起源政策的威胁模型是什么?](http://stackoverflow.com/q/6744283/) (22认同)
  • 我编辑并澄清:浏览器实际上在站点B执行网络提取以检查`Access-Control-Allow-Origin`标头,但是如果标头没有,它可能不会提供对站点A上的JS代码的响应允许站点A拥有它.(PS谢谢:)) (8认同)
  • 但MyCode.js首先无法访问B站点!这个标题将如何到达客户端?顺便说一下,在化身中为光明生命滑翔机赢得荣誉. (4认同)
  • 在使用身份验证的情况下,`Access-Control-Allow-Origin`在某些浏览器(FF和Chrome AFAIK)中不接受`*`.因此,在这种情况下,您必须指定`Origin`标头中的值.希望这会对某人有所帮助. (3认同)
  • 实际上,除非交叉原始请求获得批准,否则我在Fiddler中看不到任何下载记录.有趣... (2认同)
  • 那么为什么当我在 URL 中键入 HTTP get 请求并检索 JSON 数据时,我的浏览器可以发出 HTTP get 请求,而我的 javascript 客户端却不能呢? (2认同)
  • @Zsolti这确实是[符合规范的行为](https://www.w3.org/TR/cors/#resource-requests)("*字符串"`*`"不能用于支持凭据的资源.*").另请参见[凭证标志为true时,无法在Access-Control-Allow-Origin中使用通配符](http://stackoverflow.com/questions/19743396/cors-cannot-use-wildcard-in-access-control-allow-origin - 当-凭证标志-i)的 (2认同)
  • @NAVIN“ *这将全部完成,然后在浏览器端将拒绝请求*” –如果我理解您,这正是预检所能防止的。首先,浏览器发送预检选项,然后等待它发送实际请求,该请求将触发服务器上的某些操作。如果服务器通过发送适当的CORS响应*不*说“是,发送真实请求”,则浏览器将不会发送真实请求。 (2认同)
  • @Ashfaque (1) Chrome 扩展程序可能会以普通网页无法做到的方式[请求访问特定来源的权限](https://developer.chrome.com/extensions/xhr)。(2) OAuth 等登录 API 不使用 XHR/Ajax。他们实际上将顶级页面重定向到其他页面,例如“https://google.com/auth?token=...&redirect=...”,这种方式不会导致跨域请求。 (2认同)
  • 为了完整起见,对于动态使用“ access-control-allow-origin”(根据请求的来源更改URL值)而不是“ *”的任何人,还必须包括标头“ Vary:Origin”。参见https://fetch.spec.whatwg.org/#cors-protocol-and-http-caches (2认同)

Way*_* Ye 115

跨域请求共享 - CORS(AKA跨域AJAX请求)是大多数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 
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我上面标记的蓝色部分是核心事实,"Origin"请求标题"指示跨源请求或预检请求源自的位置","Access-Control-Allow-Origin"响应标头指示此页面允许来自远程请求DomainA(如果值为*指示允许来自任何域的远程请求).

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

OPTIONS DomainB.com/foo.aspx HTTP/1.1
Run Code Online (Sandbox Code Playgroud)

如果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
Run Code Online (Sandbox Code Playgroud)

仅当响应包含"Access-Control-Allow-Origin"并且其值为"*"或包含提交CORS请求的域时,通过满足此mandtory条件,浏览器将提交实际的跨域请求,并缓存结果在" Preflight-Result-Cache "中.

我在三年前写了关于CORS的博客:AJAX Cross-Origin HTTP请求


Pmp*_*mpr 51

问题有点太老了,无法回答,但我发布这个问题是为了将来对这个问题的任何参考.

根据这个 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. 服务器service.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: *` 的否定 (3认同)
  • 如何设置 none (2认同)
  • 只是不要为此设置任何东西 (2认同)

Dom*_*Dom 20

每当我开始考虑CORS时,我对哪个站点承载标题的直觉是不正确的,就像您在问题中所描述的那样.对我来说,考虑同一起源政策的目的是有帮助的.

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

有时您需要跨域工作,这是CORS的用武之地.CORS放宽了domainA.com的相同原始策略,使用Access-Control-Allow-Origin标头列出了可信赖运行可以与domainA交互的JavaScript的其他域(domainB.com). COM.

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

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

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

Ben*_*Ben 12

根据我自己的经验,很难找到一个简单的解释,为什么 CORS 甚至是一个问题。

一旦你理解了它为什么在那里,标题和讨论就会变得更加清晰。我将在几行中试一试。


这都是关于饼干的。Cookie 由其域存储在客户端上。

一个示例故事:在您的计算机上,有一个 cookie 用于yourbank.com. 也许你的会话在那里。

关键点:当客户端向服务器发出请求时,它会发送该请求的域下存储的 cookie。

您已在浏览器上登录到yourbank.com。您请求查看您的所有帐户,并发送 cookie yourbank.comyourbank.com接收一堆 cookie 并发回其响应(您的帐户)。

如果另一个客户端向服务器发出跨源请求,则这些 cookie 会像以前一样发送。呵呵呵。

您浏览到malicious.com. 恶意向不同的银行发出一堆请求,包括yourbank.com.

由于 cookie 已按预期进行验证,因此服务器将授权响应。

这些 cookie 被收集起来并一起发送 - 现在,malicious.com有来自yourbank.

哎呀。


所以现在,一些问题和答案变得显而易见:

  • “为什么我们不阻止浏览器这样做呢?” 是的。CORS。
  • “我们如何绕过它?” 让服务器告诉请求 CORS 正常。

  • 后端只能看到来自一个 URL 的一个请求。“yourbank.com”的后端(明确)不知道是“malicious.com”发出请求。浏览器是唯一跟踪您访问过的所有不同域的地方 (2认同)

Dha*_*osh 9

使用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);
  }
Run Code Online (Sandbox Code Playgroud)

  • 请不要这样做.使用代理链接就像将用户cookie交给中间人一样.应该是非法恕我直言 (11认同)

Osa*_*gin 8

1.客户端从http:// siteA下载javascript代码MyCode.js - 原点.

执行下载的代码 - 您的html脚本标记或来自javascript或其他的xhr - 来自,例如,http:// siteZ.并且,当浏览器请求MyCode.js时,它会发送一个Origin:标题,说"Origin:http:// siteZ ",因为它可以看到您正在请求siteA和siteZ!= siteA.(你无法阻止或干扰这一点.)

2. MyCode.js的响应头包含Access-Control-Allow-Origin:http:// siteB,我认为这意味着允许MyCode.js对站点B进行跨源引用.

没有.这意味着,只允许siteB执行此请求.因此,您对siteZ的MyCode.js请求会收到错误,而浏览器通常不会给您任何信息.但是,如果您让服务器返回ACAO:siteZ,您将获得MyCode.js.或者,如果它发送'*',那将会工作,那将让所有人进入.或者如果服务器总是从Origin:标头发送字符串......但是......为了安全起见,如果你害怕黑客,您的服务器应该只允许来自候选名单的来源,允许发出这些请求.

然后,MyCode.js来自siteA.当它向siteB发出请求时,它们都是跨域的,浏览器发送Origin:siteA,而siteB必须获取siteA,在允许的请求者的简短列表中识别它,并发送回ACAO:siteA.只有这样,浏览器才会让您的脚本获得这些请求的结果.


Mau*_*chi 8

如果您只想测试浏览器阻止请求的跨域应用程序,那么您只需在不安全模式下打开浏览器并测试应用程序,而无需更改代码,也不会使代码不安全.从MAC OS,您可以从终端线执行此操作:

open -a Google\ Chrome --args --disable-web-security --user-data-dir
Run Code Online (Sandbox Code Playgroud)


Mel*_*ero 7

如果您使用的是PHP,请尝试在php文件的开头添加以下代码:

如果使用本地主机,请尝试以下操作:

header("Access-Control-Allow-Origin: *");
Run Code Online (Sandbox Code Playgroud)

如果使用服务器等外部域,请尝试以下操作:

header("Access-Control-Allow-Origin: http://www.website.com");
Run Code Online (Sandbox Code Playgroud)


pea*_*een 7

在 Python 中,我一直在使用这个Flask-CORS并取得了巨大的成功。它使处理 CORS 变得非常简单和轻松。我从下面的库文档中添加了一些代码。

安装:

$ pip install -U flask-cors
Run Code Online (Sandbox Code Playgroud)

允许对所有路由上的所有域进行 CORS 的简单示例:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"
Run Code Online (Sandbox Code Playgroud)

有关更具体的示例,请参阅文档。我使用上面的简单示例来解决我正在构建的必须访问单独的烧瓶服务器的离子应用程序中的 CORS 问题。


izi*_*k f 5

我使用快递4和节点7.4和角度,我有同样的问题,我帮助这个:
a)服务器端:在文件app.js我给所有响应的标题如:

app.use(function(req, res, next) {  
      res.header('Access-Control-Allow-Origin', req.headers.origin);
      res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
      next();
 });  
Run Code Online (Sandbox Code Playgroud)

这必须在所有路由器之前.
我看到很多添加此标题:

res.header("Access-Control-Allow-Headers","*");
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
Run Code Online (Sandbox Code Playgroud)

但我不需要那个,
b)客户端:在发送ajax时你需要添加:"withCredentials:true",如:

$http({
     method: 'POST',
     url: 'url, 
     withCredentials: true,
     data : {}
   }).then(function(response){
        // code  
   }, function (response) {
         // code 
   });
Run Code Online (Sandbox Code Playgroud)

祝好运.

  • `res.header('Access-Control-Allow-Origin', req.headers.origin);` 与 `res.header('Access-Control-Allow-Origin', '*');` 相同 (2认同)

小智 5

只需将以下代码粘贴到您的web.config文件中。

请注意,您必须将以下代码粘贴到<system.webServer>标签下

<httpProtocol>
  <customHeaders>
   <add name="Access-Control-Allow-Origin" value="*" />
   <add name="Access-Control-Allow-Headers" value="Content-Type" />
   <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
  </customHeaders>
</httpProtocol>
Run Code Online (Sandbox Code Playgroud)


Ehs*_*Ali 5

我无法在后端服务器上配置它,但是通过浏览器中的这些扩展,它对我有用:

对于火狐浏览器:

CORS 无处不在

对于谷歌浏览器:

允许 CORS:访问控制允许来源

注意:CORS 适用于我的以下配置:

允许 CORS 选项

CORS 无处不在选项


归档时间:

查看次数:

1444905 次

最近记录:

5 年,9 月 前