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

问题描述 投票:949回答:13

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

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

好吧,我错了。它根本不起作用。所以,我读过Cross-origin resource sharing并试图阅读Cross-Origin Resource Sharing in w3c recommendation

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

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

附:

我不想使用JSONP。

javascript cross-domain cors
13个回答
1257
投票

Access-Control-Allow-Origin是一个CORS (Cross-Origin Resource Sharing) header

当站点A尝试从站点B获取内容时,站点B可以发送一个Access-Control-Allow-Origin响应头,告诉浏览器该页面的内容可以访问某些来源。 (原点是domain, plus a scheme and port number。)默认情况下,站点B的页面是not accessible to any other origin;使用Access-Control-Allow-Origin标题为特定请求来源的跨源访问打开了一扇门。

对于站点B希望对站点A可访问的每个资源/页面,站点B应为其页面提供响应头:

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

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

Non-simple requests

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

  • 使用GET或POST以外的HTTP动词(例如PUT,DELETE)
  • 使用非简单的请求标头;唯一简单的请求标头是: Accept Accept-Language Content-Language Content-Type(当它的值为application/x-www-form-urlencodedmultipart/form-datatext/plain时,这只是简单的)

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

假设站点A想要发送/somePage的PUT请求,并且Content-Type的非简单application/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

有关非简单请求的更多信息,请参阅Understanding XMLHttpRequest over CORS


3
投票

在Python中,我一直在使用header("Access-Control-Allow-Origin: http://www.website.com"); 取得巨大成功。它使处理CORS超级简单,无痛。我在下面的库文档中添加了一些代码。

安装:

Flask-CORS library

允许所有路径上所有域的CORS的简单示例:

$ pip install -U flask-cors

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


2
投票

对于跨源共享,请设置标题:from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) @app.route("/") def helloWorld(): return "Hello, cross-origin-world!"

Php:'Access-Control-Allow-Origin':'*';

因为:kuzxsw点

这将允许共享不同域的内容。


2
投票

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

注意,您必须在header('Access-Control-Allow-Origin':'*');标记下粘贴以下代码

app.use('Access-Control-Allow-Origin':'*');

0
投票

Access-Control-Allow-Origin响应头指示是否可以与来自给定源的请求代码共享响应。

<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>  

欲了解更多信息,请访问Header type Response header Forbidden header name no ....


111
投票

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

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

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

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

机制

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

域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请求之前实现“预检请求”,简而言之,它是一个HTTP qazxsw foi请求:

OPTIONS

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

OPTIONS DomainB.com/foo.aspx HTTP/1.1

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

我在三年前写过关于CORS的博客: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


45
投票

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

根据AJAX Cross-Origin HTTP request Mozilla开发者网络文章,

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

this

enter image description here提供的HTML页面为http://domain-a.com提出了<img> src请求。 今天网络上的许多页面都加载了来自不同域的CSS样式表,图像和脚本等资源(因此它应该很酷)。

Same-Origin Policy

出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。 例如,http://domain-b.com/image.jpgXMLHttpRequest遵循同源策略。 因此,使用FetchXMLHttpRequest的Web应用程序只能向自己的域发出HTTP请求。

Cross-Origin Resource Sharing (CORS)

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

跨源资源共享(CORS)机制为Web服务器提供跨域访问控制,从而实现安全的跨域数据传输。 现代浏览器在API容器中使用CORS(例如FetchXMLHttpRequest)来降低跨源HTTP请求的风险。

CORS如何工作(Fetch标题)

Access-Control-Allow-Origin

CORS标准描述了新的HTTP标头,它为浏览器和服务器提供了一种仅在有权限时才能请求远程URL的方法。

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

Example

  1. 浏览器使用Wikipedia标头发送OPTIONS请求。 此标头的值是为父页面提供服务的域。当Origin HTTP的页面尝试访问http://www.example.com中的用户数据时,以下请求标头将发​​送到service.example.com: 起源:service.example.com
  2. http://www.example.com的服务器可能会回复: 其响应中的service.example.com(ACAO)标头指示允许哪些源站点。 例如: Access-Control-Allow-Origin 如果服务器不允许跨源请求,则为错误页面 带有通配符的Access-Control-Allow-Origin: http://www.example.com(ACAO)标头,允许所有域: Access-Control-Allow-Origin

16
投票

每当我开始考虑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: *标头列出其他域(domainB.com),这些域可信赖运行可与域A交互的JavaScript .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来允许它们吗?


8
投票

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

Access-Control-Allow-Origin

8
投票

使用React和Axios,将代理链接加入URL并添加标题,如下所示

open -a Google\ Chrome --args --disable-web-security --user-data-dir + https://cors-anywhere.herokuapp.com/

只需添加代理链接即可,但它也可以再次为无访问权限抛出错误。因此最好添加标题,如下所示。

Your API URL

6
投票

1.客户端从axios.get(`https://cors-anywhere.herokuapp.com/[YOUR_API_URL]`,{headers: {'Access-Control-Allow-Origin': '*'}}) .then(response => console.log(response:data); } 下载javascript代码MyCode.js - 原点。

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

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

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

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


6
投票

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

http://siteB

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

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();
 });  

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

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

祝好运。


4
投票

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

如果您使用的是localhost,请尝试以下操作:

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

如果您使用的是外部域,例如服务器,请尝试以下操作:

header("Access-Control-Allow-Origin: *");
© www.soinside.com 2019 - 2024. All rights reserved.