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

时间:2012-05-17 13:23:54

标签: 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的某些功能,而MyCode.js又向http:// siteB发出请求,尽管是跨源请求,但这应该没问题。
  4. 嗯,我错了。它根本不起作用。所以,我已阅读Cross-origin resource sharing并尝试阅读Cross-Origin Resource Sharing in w3c recommendation

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

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

    P.S。

    我不想使用JSONP。

17 个答案:

答案 0 :(得分:1216)

Access-Control-Allow-OriginCORS (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访问此页面,则浏览器将触发XMLHttpRequest的{​​{1}}事件,并拒绝响应请求的JavaScript代码的响应数据。

非简单请求

网络级别上发生的事情可能略微比上面解释的更复杂。如果请求是"non-simple" request,则浏览器首先发送无数据“预检”OPTIONS请求,以验证服务器是否接受请求。当(或两者):

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

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

假设网站A想要发送Access-Control-Allow-Methods的PUT请求,且/somePage值非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-Method;你不需要添加它们。此OPTIONS预检获得成功的响应标题:

Access-Control-Request-Headers

发送实际请求时(预检完成后),行为与处理简单请求的行为相同。换句话说,预检成功的非简单请求与简单请求相同(即,服务器仍必须再次发送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

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

答案 1 :(得分:108)

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

  1. 使用Flash / Silverlight或服务器端作为“代理”进行通信 与远程。
  2. 带填充的JSON(JSONP)。
  3. 在iframe中嵌入远程服务器并通过fragment或window.name进行通信,请参阅here
  4. 这些棘手的方式或多或少存在一些问题,例如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请求之前实现“预检请求”,简而言之,它是HTTP OPTIONS请求:< / p>

    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请求的域时,通过满足此mandtory条件,浏览器将提交实际的跨域请求,并且将结果缓存在“预检 - 结果 - 缓存”中。

    三年前我在博客上发表了关于CORS的文章:AJAX Cross-Origin HTTP request

答案 2 :(得分:43)

问题有点太陈旧,无法回答,但我发布此信息是为了将来对此问题的任何参考。

根据this Mozilla开发者网络文章,

  

资源在从第一个资源本身所服务的域或端口请求资源时,会生成跨源HTTP请求

enter image description here

http://domain-a.com提供的 HTML网页<img>发出http://domain-b.com/image.jpg src请求。
今天网络上的许多网页都会从不同的域中加载 CSS样式表图片脚本等资源(因此应该很酷)。

同源政策

出于安全原因,浏览器限制从脚本中发起的跨源HTTP 请求
例如,XMLHttpRequestFetch遵循同源政策 因此,使用XMLHttpRequestFetch的网络应用只能将 HTTP请求发送到自己的域

跨源资源共享(CORS)

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

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

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

Wikipedia

  

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

答案 3 :(得分:12)

每当我开始考虑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)运行可以与domainA.com交互的JavaScript。

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

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

答案 4 :(得分:8)

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

open -a Google\ Chrome --args --disable-web-security --user-data-dir

答案 5 :(得分:7)

使用 React Axios ,加入代理链接到网址并添加标题,如下所示

df = df.apply(str) print(df.iloc[1]) '456' + https://cors-anywhere.herokuapp.com/

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

Your API URL

答案 6 :(得分:6)

我使用快递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();
 });  

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

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

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

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

答案 7 :(得分:6)

1。客户端从http://siteA下载javascript代码MyCode.js - 来源。

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

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

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

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

答案 8 :(得分:3)

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

如果您使用的是localhost,请尝试:

header("Access-Control-Allow-Origin: *");

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

header("Access-Control-Allow-Origin: http://www.website.com");

答案 9 :(得分:3)

在Python中,我一直在使用Flask-CORS library取得巨大成功。它使处理CORS超级简单,无痛。我在下面的库文档中添加了一些代码。

安装:

$ pip install -U flask-cors

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

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

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

答案 10 :(得分:2)

对于跨源共享,请设置标题:'Access-Control-Allow-Origin':'*';

Php:header('Access-Control-Allow-Origin':'*');

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

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

答案 11 :(得分:1)

只需将以下代码粘贴到您的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>  

答案 12 :(得分:1)

Nginx和方法

除了apsillers answer外,我想添加wiki graph来显示请求是否简单(以及是否发送OPTIONS飞行前请求)

Enter image description here

对于简单的请求(例如hotlinking images),您无需更改服务器配置文件,但可以在应用程序中添加标头(托管在服务器中,例如php中),例如Melvin Guerrero在其{{3 }}-但是answer:如果您在服务器(配置)中添加完整的cors标头,并且同时允许在应用程序(例如php)上使用简单的cors,则根本无法使用。

这是两个流行服务器的配置

  • 在Nginx上打开 CORS nginx.conf文件)

    location ~ ^/index\.php(/|$) {
       ...
        add_header 'Access-Control-Allow-Origin' "$http_origin" always; # if you change "$http_origin" to "*" you shoud get same result - allow all domain to CORS (but better change it to your particular domain)
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        if ($request_method = OPTIONS) {
            add_header 'Access-Control-Allow-Origin' "$http_origin"; # DO NOT remove THIS LINES (doubled with outside 'if' above)
            add_header 'Access-Control-Allow-Credentials' 'true';
            add_header 'Access-Control-Max-Age' 1728000; # cache preflight value for 20 days
            add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';  # arbitrary methods
            add_header 'Access-Control-Allow-Headers' 'My-First-Header,My-Second-Header,Authorization,Content-Type,Accept,Origin'; # arbitrary headers
            add_header 'Content-Length' 0;
            add_header 'Content-Type' 'text/plain charset=UTF-8';
            return 204;
        }
    }

  • 在Appache上打开 CORS .htaccess文件)

    # ------------------------------------------------------------------------------
    # | Cross-domain Ajax requests                                                 |
    # ------------------------------------------------------------------------------
    
    # Enable cross-origin Ajax requests.
    # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity
    # http://enable-cors.org/
    
    # change * (allow any domain) below to your domain
    Header set Access-Control-Allow-Origin "*"
    Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
    Header always set Access-Control-Allow-Headers "My-First-Header,My-Second-Header,Authorization, content-type, csrf-token"
    Header always set Access-Control-Allow-Credentials "true"

答案 13 :(得分:1)

谁无法控制Options 405 Method Not Allowed的后端。
Chrome浏览器的解决方法。
在命令行中执行:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="path_to_profile"
示例:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir="C:\Users\vital\AppData\Local\Google\Chrome\User Data\Profile 2"

答案 14 :(得分:0)

  

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

Header type Response       header
Forbidden header name      no
  

一个响应,告诉浏览器允许将任何来源的代码   访问资源将包括以下内容:

Access-Control-Allow-Origin: *

有关更多信息,请访问here。...

答案 15 :(得分:0)

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

一旦您了解了它的存在原因,标题和讨论就会变得更加清晰。我会在几行中试一下。


这全都与cookie有关。 Cookies按其域存储在客户端上。

  

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

当客户端向服务器发出请求时,它将发送存储在该域下的cookie。

  

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

然后其他站点可以向服务器发出跨源请求,并且与以前一样发送cookie。

  

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

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

  

这些cookie被收集起来并一起发送-现在,malicious.com得到了yourbank的回应。

喜欢。


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

  • “为什么我们不阻止浏览器执行此操作?”是的CORS。
  • “我们如何解决它?”让服务器告知请求CORS正常。

答案 16 :(得分:0)

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

对于 Firefox: Cors Everywhere

对于谷歌浏览器: Allow CORS: Access-Control-Allow-Origin

注意:CORS 使用此配置对我有用:

Allow CORS options

CORS Everywhere options