XMLHttpRequest无法加载https:// www。 .com /

我有一个Grunt进程启动一个express.js服务器的实例。 直到现在,它开始提供一个空白页面,并且在Chrome(最新版本)的开发者控制台的错误日志中出现以下内容:

XMLHttpRequest无法加载https:// www。[website] .com /否请求的资源上存在“Access-Control-Allow-Origin”标头。 原因' http:// localhost:4300 '因此不被允许访问。

什么阻止我访问页面?

关于同源政策

这是同源政策 。 这是一个由浏览器实现的安全function。

您的具体情况是如何实现XMLHttpRequest(如果您要使用fetch,您将获得相同的结果),但也适用于其他事物(例如加载到<canvas>图像或加载到<iframe> ),只是略有不同的实现。

演示SOP需求的标准scheme可以用三个字符来演示:

  • 爱丽丝是一个拥有networking浏览器的人
  • Bob运行一个网站( https://www.[website].com/在你的例子中)
  • Mallory运行一个网站(在你的例子中是http://localhost:4300

AliceloginBob的网站,并在那里有一些机密的数据。 也许这是一个公司内联网(只能访问局域网上的浏览器),或者她的网上银行(只有input用户名和密码后才能访问的cookie)。

Alice访问Mallory的网站,该网站上有一些JavaScript,导致Alice的浏览器向Bob的网站发送一个HTTP请求(从她的cookie和她的IP地址等)。 这可以像使用XMLHttpRequest和读取responseText一样简单。

浏览器的同源策略阻止了JavaScript读取Bob网站(Bob和Alice不希望Mallory访问)返回的数据。 (请注意,例如,您可以在原始<img>使用<img>元素显示图像,因为图像的内容不会暴露给JavaScript(或Mallory)…除非您将canvas放入混合中,在这种情况下,您生成同源违规错误)。


为什么同源政策适用于你不这样认为的情况

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

  • 爱丽丝,鲍勃和马洛里是同一个人。
  • 鲍勃提供完全公开的信息

…但浏览器无法知道以上两种情况是否属实,因此信任不是自动的,并且SOP被应用。 在浏览器将数据提供给其他网站之前,必须明确授予权限。


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

浏览器扩展,浏览器开发人员工具和应用程序(如邮差)中的networking选项卡是已安装的软 他们不会仅仅因为您访问了不同的网站而将数据从一个网站传递到属于不同网站的JavaScript。 安装软件通常需要更有意识的select。

没有被认为是风险的第三方(马洛里)。


为什么你可以在页面中显示数据,而不用JS读取数据

在许多情况下,Mallory的网站可以让浏览器从第三方获取数据并显示数据(例如,通过添加<img>元素来显示图像)。 Mallory的JavaScript不可能读取资源中的数据,只有Alice的浏览器和Bob的服务器可以这样做,所以它仍然是安全的。


CORS

错误消息中提到的Access-Control-Allow-Origin标头是CORS标准的一部分,它允许Bob明确授予Mallory的站点访问Alice的浏览器访问数据的权限。

一个基本的实现将包括:

 Access-Control-Allow-Origin: * 

…允许任何网站读取数据。

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

…将只允许特定的站点访问它,并且可以根据Origin 请求标头dynamic生成该站点,以允许多个(但不是全部)站点访问它。

您如何设置响应头文件的具体细节取决于Bob的HTTP服务器和/或服务器端编程语言。 有各种常见configuration可能有帮助的指南集合 。

注意:一些请求是复杂的,并发送一个预检 OPTIONS请求,服务器在浏览器发送GET / POST / PUT / Whatever要求的任何请求之前必须做出响应。 仅将Access-Control-Allow-Origin到特定URL的CORS实现通常会被这个事件绊倒。


显然通过CORS授予权限是Bob只有在以下情况下才能做到的:

  • 数据不是私人的
  • 马洛里是值得信赖的

如果在这种情况下你也是Bob,那么添加CORS权限头文件的具体细节将取决于你select的HTTP服务器软件的某种组合,以及你用于服务器端编程的语言(如果有的话)。

马洛里不能添加这个标题,因为她必须得到鲍勃的网站的许可,如果她能够授予自己的许可,这将是愚蠢的(为了使SOP无用)。


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

一些交叉来源请求是预检的 。

发生这种情况时(粗略地说)你尝试做一个交叉来源的请求:

  • 包括cookie等凭据
  • 无法使用常规HTML表单生成(例如,具有自定义标题或无法在表单的enctype使用的Content-Type)。

在这些情况下,这个答案的其余部分仍然适用,但你还需要确保服务器可以侦听预检请求(这将是OPTIONS (而不是GETPOST或任何你想发送的)并响应它使用正确的Access-Control-Allow-Origin头部,还可以Access-Control-Allow-MethodsAccess-Control-Allow-Headers来允许使用特定的HTTP方法或头部。


CORS的替代品

JSONP

Bob也可以使用像JSONP这样的黑客技术来提供数据,这就是人们在CORS出现之前做了跨源Ajax的过程。

它通过以JavaScript程序的forms呈现数据,将数据注入Mallory的页面。

它要求马洛里信任鲍勃不要提供恶意代码。

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

将这两个资源移动到一个Origin

如果JS运行的HTML文档和被请求的URL在相同的源(共享相同的scheme,主机名和端口),那么它们相同的来源策略默认授予权限。 CORS是不需要的。

代理

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

它将会:

  • 添加CORS标题
  • 将响应转换为JSONP
  • 存在于与HTML文档相同的来源

该服务器端代码可以由第三方托pipe(如YQL)。

鲍勃不需要授予任何权限发生。

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

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

写一个webapp以外的东西

正如“为什么同源策略只适用于网页中的JavaScript”部分所述,您可以通过不在网页中编写JavaScript来避免SOP。

这并不意味着您不能继续使用JavaScript和HTML,但可以使用其他机制(如Node-WebKit或PhoneGap)来分发它。

浏览器扩展

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

这对于开发很有用,但对于一个防护网站来说是不实用的(要求你的网站的每个用户安装一个浏览器扩展,禁止浏览器的安全function是不合理的)。

他们也倾向于只处理简单的请求(在处理预检选项请求时失败)。

通过本地开发服务器获得适当的开发环境通常是更好的方法。


其他安全风险

请注意,SOP / CORS不会减轻需要独立处理的XSS , CSRF或SQL注入攻击。


概要

  • 你的客户端代码中没有任何东西可以让CORS访问别人的服务器。
  • 如果您控制服务器,请求正在向其添加CORS权限。
  • 如果你对控制它的人友好:让他们添加CORS权限。
  • 如果是公共服务:阅读他们的API文档,看看他们如何用客户端JavaScript访问它。 他们可能会告诉您使用特定的URL或使用JSONP(或者他们可能根本不支持)。
  • 如果以上都不适用:取而代之的是浏览器与服务器交谈,然后让服务器从其他服务器获取数据并传递给服务器。 (也有第三方托pipe的服务攻击CORS头到公用可访问的资源,你可以使用)。

这是由于CORS错误发生的。 CORS代表跨源资源共享。 简而言之,当我们尝试从另一个域访问一个域/资源时会发生这个错误。

在这里阅读更多关于它: 与jQuery的CORS错误

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

如何获得跨源资源共享(CORS)的后期请求工作

这些链接可能有帮助

因为这在接受的答案中没有提到。

  • 对于这个确切的问题,情况并非如此,但可能会帮助其他人寻找这个问题
  • 您可以在客户端代码中执行此操作,以防止某些情况下发生CORS错误。

如果服务器所有者没有以某种方式显式阻止它,则可以使用简单请求 。
请注意,“简单的请求”需要满足几个条件,包括只允许POSTGETHEAD ,以及只允许某些给定的头(你可以在这里find所有的条件)。

如果您的客户端代码没有在请求中设置受影响的Header,并且修复了这个值, 可能会发生这样的情况:某些客户端会自动使用一些“非标准”值设置这些Headers,导致服务器不接受它作为简单的请求 – 这会给您一个CORS错误。

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

这是一个关于stackoverflow的相关问题。

目标服务器必须允许跨源请求。 为了让它通过快递,只需处理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); }); 

你应该启用CORS来使它工作。