首页 文章

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

提问于
浏览
849

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

  • 客户端从http:// siteA - the origin 下载javascript代码MyCode.js .

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

  • 客户端触发MyCode.js的一些功能,而MyCode.js又向http:// siteB发出请求,尽管是跨源请求,但这应该没问题 .

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

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

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

附:

我不想使用JSONP .

11 回答

  • 2

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

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

    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 Headers 为特定请求来源的跨域访问打开了一扇门 .

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

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

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

    非简单请求

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

    • 使用GET或POST以外的HTTP动词(例如PUT,DELETE)

    • 使用非简单请求标头;唯一简单的请求标头是:

    • Accept

    • Accept-Language

    • Content-Language

    • Content-Type (当它的值为 application/x-www-form-urlencodedmultipart/form-datatext/plain 时,这只是简单的)

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

    假设站点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 .

  • 1097

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

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

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

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

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

    根据Same-Origin-Policy,浏览器限制安全沙箱中的客户端JavaScript,通常JS无法直接与远程通信来自不同域的服务器 . 在过去,开发人员创建了许多棘手的方法来实现跨域资源请求,最常用的方法是:

    • 使用Flash / Silverlight或服务器端作为"proxy"与远程通信 .

    • 带填充的JSON(JSONP) .

    • 在iframe中嵌入远程服务器并通过fragment或window.name进行通信,请参阅here .

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

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

    The Mechanism

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

    DomainA AJAX request headers

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

    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”请求 Headers “指示跨源请求或预检请求源自的位置”,“Access-Control-Allow-Origin”响应标头指示此页面允许来自远程请求DomainA(如果值为*指示允许来自任何域的远程请求) .

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

    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条件,浏览器将提交实际的跨域请求,并将结果缓存在“ Preflight-Result-Cache ”中 .

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

  • 8

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

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

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

    enter image description here

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

    同源政策

    出于安全原因,浏览器会限制 cross-origin HTTP 个请求 initiated from within scripts .
    例如, XMLHttpRequestFetch 遵循 same-origin policy .
    因此,使用 XMLHttpRequestFetch 的Web应用程序只能 HTTP requestsits own domain .

    跨源资源共享(CORS)

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

    Cross-Origin Resource Sharing (CORS) 机制提供Web服务器 cross-domain access controls ,它可以实现安全的跨域数据传输 .
    现代浏览器在 API container 中使用 CORS (例如 XMLHttpRequestFetch )来降低跨源HTTP请求的风险 .

    CORS如何工作(Access-Control-Allow-Origin标头)

    Wikipedia

    CORS标准描述了新的HTTP标头,它为浏览器和服务器提供了一种仅在获得许可时才能请求远程URL的方法 . 虽然服务器可以执行某些验证和授权,但浏览器通常负责支持这些标头和荣誉他们施加的限制 .

    示例

    • 浏览器使用 Origin HTTP 标头发送 OPTIONS 请求 .

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

    原产地:http://www.example.com

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

  • 105

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

    同一原始策略的目的是保护您免受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 标头列出了可信赖运行可与域A交互的JavaScript的其他域(domainB.com) .COM .

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

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

  • 37

    在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问题,该应用程序必须访问单独的烧瓶服务器 .

  • 2

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

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

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

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

  • 8

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

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

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

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

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

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

    1. MyCode.js的响应头包含Access-Control-Allow-Origin:http://siteB,我认为这意味着允许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 . 只有这样,浏览器才会让您的脚本获得这些请求的结果 .

  • 5

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

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

    this must have before all router .
    我看到很多添加此 Headers :

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

    祝好运 .

相关问题