首页 文章

XMLHttpRequest无法加载XXX No 'Access-Control-Allow-Origin'标头

提问于
浏览
58

tl;博士;关于同源政策

我有一个Grunt进程,它启动了express.js服务器的一个实例 . 刚刚开始提供空白页面,并且Chrome浏览器控制台(最新版本)中的错误日志中出现以下内容时,这一点工作非常精细:

XMLHttpRequest无法加载https://www.example.com/请求的资源上没有“Access-Control-Allow-Origin”标头 . 因此不允许来源'http:// localhost:4300'访问 .

什么阻止我访问该页面?

5 回答

  • 2

    关于同源政策

    这是Same Origin Policy . 它是由浏览器实现的安全功能 .

    您的具体案例展示了如何为XMLHttpRequest实现它(如果您使用fetch,您将获得相同的结果),但它也适用于其他事物(例如加载到 <canvas> 的图像或加载到 <iframe> 的文档),只是略有不同的实现 .

    (奇怪的是,它也适用于CSS字体,但这是因为找到的代工厂坚持使用DRM而不是同源策略通常涵盖的安全问题) .

    可以使用three characters演示用于演示SOP需求的标准方案:

    • Alice是拥有网络浏览器的人

    • Bob运行一个网站(在您的示例中为 https://www.[website].com/

    • Mallory运行一个网站(在您的示例中为 http://localhost:4300

    Alice登录Bob的网站,并在那里有一些机密数据 . 也许它是一个公司内部网(只能访问局域网上的浏览器)或她的网上银行(只能通过输入用户名和密码后获得的cookie访问) .

    Alice访问Mallory 's website which has some JavaScript that causes Alice'浏览器,向Bob的网站发出HTTP请求(来自她的IP地址及其cookie等) . 这可以像使用 XMLHttpRequest 并阅读 responseText 一样简单 .

    浏览器's Same Origin Policy prevents that JavaScript from reading the data returned by Bob'的网站(Bob和Alice不希望Mallory访问) . (请注意,例如,您可以跨源使用 <img> 元素显示图像,因为图像的内容不会暴露给JavaScript(或Mallory)...除非您将画布投入混合,在这种情况下您将生成相同的 - 原产地违规错误) .


    为什么同源原则政策适用于您认为不应该的原因

    对于任何给定的URL,可能不需要SOP . 在这种情况下,有几种常见情况是:

    • Alice,Bob和Mallory是同一个人 .

    • 鲍勃正在提供完全公开的信息

    ...但是浏览器无法知道上述任何一个是否属实,因此信任不是自动的并且应用了SOP . 必须在浏览器将给出的数据提供给其他网站之前明确授予权限 .


    为什么同源策略仅适用于网页中的JavaScript

    浏览器扩展,浏览器开发工具中的网络选项卡和Postman等应用程序都是安装软件 . 他们没有将数据从一个网站传递到属于不同网站的JavaScript,只是因为您访问了不同的网站 . 安装软件通常需要更有意识的选择 .

    没有第三方(Mallory)被视为风险 .


    为什么你可以在不用JS阅读的情况下在页面中显示数据

    在许多情况下,Mallory的网站可以使浏览器从第三方获取数据并显示它(例如,通过添加 <img> 元素来显示图像) . 虽然没有't possible for Mallory'的JavaScript来读取该资源中的数据,但只有Alice 's browser and Bob'的服务器才能这样做,因此它仍然是安全的 .


    CORS

    错误消息中引用的 Access-Control-Allow-Origin 标头是CORS标准的一部分,允许Bob明确授予Mallory 's site to access the data via Alice'浏览器的权限 .

    基本实现只包括:

    Access-Control-Allow-Origin: *
    

    ......允许任何网站阅读数据 .

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

    ...只允许特定站点访问它,您可以根据 Origin 请求标头动态生成该站点,以允许多个(但不是所有)站点访问它 .

    您如何设置响应头的具体细节取决于Bob的HTTP服务器和/或服务器端编程语言 . 有a collection of guides for various common configurations可能会有所帮助 .

    注意:有些请求很复杂,并发送一个preflight OPTIONS请求,服务器必须在浏览器发送GET / POST / PUT /无论JS想要的任何请求之前做出响应 . 仅将 Access-Control-Allow-Origin 添加到特定URL的CORS实现通常会因此而被绊倒 .


    显然,通过CORS授予权限是Bob只有在以下情况之一时才会执行的操作:

    • 数据不是私有的或

    • 马洛里值得信赖

    如果您在这种情况下也是Bob,那么您添加CORS权限标头的具体细节将取决于您选择的HTTP服务器软件的某些组合以及您用于服务器端编程的语言(如果任何) .

    马洛里可以't add this header because she has to get permission from Bob'的网站,这将是愚蠢的(为了使SOP无用),以便她能够授予自己许可 .


    提及“预检响应”的错误消息

    一些跨源请求是preflighted .

    这种情况发生在(粗略地说)您尝试制作跨源请求时:

    • 包括Cookie等凭据

    • 在表格的 enctype 中使用't be generated with a regular HTML form (e.g. has custom headers or a Content-Type that you couldn' .

    请注意"custom headers"包括 Access-Control-Allow-Origin 和其他CORS响应头 . 这些不做任何有用的事情(你可以授予自己权限的权限系统的重点是什么?),并且必须只出现在响应上 .

    在这些情况下,然后 the rest of this answer still applies 但你还需要确保服务器可以监听预检请求(这将是 OPTIONS (而不是 GETPOST 或您尝试发送的任何内容)并使用正确的 Access-Control-Allow-Origin 标头回复它但是还 Access-Control-Allow-MethodsAccess-Control-Allow-Headers 以允许您的特定HTTP方法或标头 .


    CORS的替代品

    JSONP

    Bob也可以使用像_647711这样的黑客来提供数据,这是人们在CORS出现之前做过跨源Ajax的方式 .

    它的工作原理是以JavaScript程序的形式呈现数据,该程序将数据注入Mallory的页面 .

    它要求Mallory信任Bob不要提供恶意代码 .

    请注意常见主题:提供数据的站点必须告诉浏览器第三方站点可以访问它发送到浏览器的数据 .

    将两个资源移动到一个Origin

    如果JS运行的HTML文档和请求的URL位于同一源(共享相同的方案,主机名和端口),则默认情况下它们的Same Origin Policy授予权限 . 不需要CORS .

    A代理

    Mallory可以使用服务器端代码来获取数据(然后她可以像往常一样通过HTTP从她的服务器传递到Alice的浏览器) .

    它将:

    • 添加CORS标头

    • 将响应转换为JSONP

    • 与HTML文档存在于同一原点

    服务器端代码可以由第三方(例如YQL)托管 .

    Bob不需要为此发生任何权限 .

    这很好,因为那只是马洛里和鲍勃之间 . Bob没有办法认为Mallory是Alice,并且为Mallory提供了应该在Alice和Bob之间保密的数据 .

    因此,Mallory只能使用此技术来读取公共数据 .

    编写Web应用程序以外的内容

    如“为什么同源策略仅适用于网页中的JavaScript”一节所述,您可以通过不在网页中编写JavaScript来避免SOP .

    这并不意味着您无法继续使用JavaScript和HTML,但您可以使用其他一些机制(例如Node-WebKit或PhoneGap)进行分发 .

    浏览器扩展

    在应用同源策略之前,浏览器扩展可能会在响应中注入CORS头 .

    这些对于开发很有用,但对于 生产环境 站点不实用(要求站点的每个用户安装禁用浏览器安全功能的浏览器扩展是不合理的) .

    它们也倾向于只处理简单的请求(处理预检OPTIONS请求时失败) .

    使用本地开发服务器具有适当的开发环境通常是更好的方法 .


    其他安全风险

    请注意,SOP / CORS不会缓解需要独立处理的XSSCSRFSQL Injection攻击 .


    摘要

    • 您无法在客户端代码中执行任何操作来启用CORS访问其他人的服务器 .

    • 如果您控制服务器,则请求:向其添加CORS权限 .

    • 如果您对控制它的人很友好:让他们为其添加CORS权限 .

    • 如果是公共服务:请阅读他们的API文档,了解他们对使用客户端JavaScript访问它的看法 . 他们可能会告诉您使用特定的URL或使用JSONP(或者他们可能根本不支持它) .

    • 如果以上都不适用:让浏览器改为与您的服务器通信,然后让您的服务器从其他服务器获取数据并将其传递 . (还有第三方托管服务将CORS标头附加到您可以使用的公共可访问资源) .

  • 85

    这是因为CORS错误而发生的 . CORS代表跨源资源共享 . 简单来说,当我们尝试从另一个域访问域/资源时会发生此错误 .

    在这里阅读更多相关信息:CORS error with jquery

    要解决此问题,如果您有权访问其他域,则必须在服务器中允许Access-Control-Allow-Origin . 这可以添加到 Headers 中 . 您可以为所有请求/域或特定域启用此功能 .

    How to get a cross-origin resource sharing (CORS) post request working

    这些链接可能有帮助

  • 2

    必须允许目标服务器跨领域请求 . 为了让它通过express,只需处理http选项请求:

    app.options('/url...', function(req, res, next){
       res.header('Access-Control-Allow-Origin', "*");
       res.header('Access-Control-Allow-Methods', 'POST');
       res.header("Access-Control-Allow-Headers", "accept, content-type");
       res.header("Access-Control-Max-Age", "1728000");
       return res.sendStatus(200);
    });
    
  • 2

    因为在接受的答案中没有提到这一点 .

    • 对于这个确切的问题,情况并非如此,但可能有助于其他人搜索该问题

    • 这是您可以在客户端代码中执行的操作,以防止在某些情况下出现CORS错误 .

    如果服务器所有者没有以某种方式明确地阻止它 - 您可以使用Simple requests .
    请注意,'simple requests'需要满足几个条件,包括仅允许 POSTGETHEAD 以及仅允许某些给定的 Headers (您可以找到所有条件here) .

    如果您的客户端代码未在请求中设置具有修复值的受影响Header,则可能会发生某些客户端使用某些"non-standard"值自动设置这些Headers导致服务器不接受它作为简单请求 - 这将给您一个CORS错误 .

    这种情况的一个很好的指标可能是CORS错误,包括术语 preflight .

    This是stackoverflow上的一个相关问题 .

  • -3

    您应该启用CORS以使其正常工作 .

相关问题