Javascript XMLHttpRequest无法加载XXX号';访问控制允许原点';标题 tl;博士关于同一原产地政策

Javascript XMLHttpRequest无法加载XXX号';访问控制允许原点';标题 tl;博士关于同一原产地政策,javascript,cors,same-origin-policy,Javascript,Cors,Same Origin Policy,我有一个Grunt进程,它启动一个express.js服务器实例。直到现在,它才开始提供一个空白页面,在Chrome(最新版本)的开发人员控制台的错误日志中显示以下内容: 无法加载XMLHttpRequest 请求的服务器上不存在“Access Control Allow Origin”标头 资源。因此,不允许访问源“” 是什么阻止我访问该页面?tl;博士-在结尾有一个摘要,在答案中有标题,以便更容易找到相关部分。尽管如此,还是建议阅读所有内容,因为它为理解为什么提供了有用的背景知识,这使得了解

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

无法加载XMLHttpRequest 请求的服务器上不存在“Access Control Allow Origin”标头 资源。因此,不允许访问源“”


是什么阻止我访问该页面?

tl;博士-在结尾有一个摘要,在答案中有标题,以便更容易找到相关部分。尽管如此,还是建议阅读所有内容,因为它为理解为什么提供了有用的背景知识,这使得了解如何在不同情况下应用变得更加容易

关于同一原产地政策 这是最新的。它是由浏览器实现的安全特性

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

(奇怪的是,它也适用于CSS字体,但这是因为found Foundry坚持使用DRM,而不是出于同一原产地政策通常涵盖的安全问题)

证明需要SOP的标准场景可以通过以下方式进行演示:

  • 爱丽丝是一个有网络浏览器的人
  • 鲍勃经营一个网站(
    https://www.[website].com/
    在您的示例中)
  • 马洛里经营着一个网站(
    http://localhost:4300
    在您的示例中)
Alice登录到Bob的网站,在那里有一些机密数据。也许是公司内部网(只能通过局域网上的浏览器访问),或者是她的网上银行(只能通过输入用户名和密码后获得的cookie访问)

Alice访问Mallory的网站,该网站有一些JavaScript,使Alice的浏览器向Bob的网站发出HTTP请求(从她的IP地址和cookies等)。这可能很简单,只需使用
XMLHttpRequest
并读取
responseText

浏览器的同源策略阻止JavaScript读取Bob网站返回的数据(Bob和Alice不希望Mallory访问这些数据)。(请注意,例如,您可以使用
元素跨源显示图像,因为图像的内容不暴露于JavaScript(或Mallory)…除非您将画布放入混合,在这种情况下,您将生成相同的源冲突错误)


为什么在您认为不应该的情况下适用同一原产地政策 对于任何给定的URL,都可能不需要SOP。出现这种情况的两种常见情况是:

  • 爱丽丝、鲍勃和马洛里是同一个人
  • 鲍勃提供的是完全公开的信息
…但浏览器无法知道上述任何一项是否正确,因此信任不是自动的,而是应用SOP。在浏览器将其提供给其他网站的数据提供给其他网站之前,必须明确授予权限


为什么同源策略只适用于网页中的JavaScript 浏览器扩展
*
、浏览器开发工具中的网络选项卡和应用程序(如Postman)都是安装的软件。他们不会仅仅因为您访问了另一个网站就将数据从一个网站传递到另一个网站的JavaScript。安装软件通常需要更谨慎的选择

没有第三方(马洛里)被视为风险

*
浏览器扩展确实需要仔细编写,以避免跨源问题


为什么可以在页面中显示数据而不用JS读取 在许多情况下,Mallory的网站会导致浏览器从第三方获取数据并显示数据(例如,通过添加
元素来显示图像)。虽然Mallory的JavaScript无法读取该资源中的数据,但只有Alice的浏览器和Bob的服务器可以读取,因此它仍然是安全的


科尔斯 错误消息中提到的
Access Control Allow Origin
HTTPresponse头是标准的一部分,该标准允许Bob明确授予Mallory站点通过Alice浏览器访问数据的权限

一个基本的实施方案只包括:

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

…将只允许特定站点访问它,Bob可以基于
来源
请求头动态生成该请求,以允许多个(但不是所有)站点访问它

Bob如何设置响应头的细节取决于Bob的HTTP服务器和/或服务器端编程语言。这可能会有所帮助

注意:有些请求很复杂,在浏览器发送GET/POST/PUT/JS想要发出的任何请求之前,服务器必须响应一个选项请求。仅向特定URL添加
访问控制的COR实现通常会因此而出错


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

  • 这些数据不是私人的,也不是私人的
  • 马洛里是值得信任的

但我不是鲍勃! Mallory没有标准的机制来添加此标题,因为它必须来自Bob的网站,而Bob不控制该网站

如果Bob正在运行一个公共API,那么可能有一种机制来打开CORS(可能是通过以某种方式格式化请求,或者在登录到开发者门户后使用配置选项)
Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: http://example.com/
fetch("http://example.com", { mode: "no-cors" });
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);
});
access-control-allow-origin: origin  
Origin: http://localhost:4221
access-control-allow-origin: *  
access-control-allow-origin: http://localhost:4221