我有一个Grunt进程,它启动了一个express.js服务器的实例。直到刚才,这一切都运行得非常好,但现在它开始提供一个空白页面,并在Chrome(最新版本)的开发者控制台中的错误日志中显示以下内容:
XMLHttpRequest无法加载https://www.example.com/ 请求的资源上没有'Access-Control-Allow-Origin'头。因此,不允许来自'http://localhost:4300'的访问。
是什么阻止了我访问该页面?
目标服务器必须允许跨域请求。为了通过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); });
tl;dr — 当您想要(主要)使用客户端 JS 从不同的服务器读取数据时,您需要包含数据的服务器向需要数据的代码授予显式权限。
最后有一个摘要,答案中有标题,以便更容易找到相关部分。不过,建议阅读所有内容,因为它为理解 why 提供了有用的背景,从而使了解 how 在不同情况下如何应用变得更容易。
这是同源策略。它是浏览器实现的安全功能。
您的特殊情况显示了它是如何为 XMLHttpRequest 实现的(如果您使用 fetch,您将得到相同的结果),但它也适用于其他事物(例如加载到 上的图像) ; 或加载到 中的文档),只是实现略有不同。
上的图像) ;
演示 SOP 需求的标准场景可以用 三个字符:
https://www.example.com/
http://localhost:4300
Alice 登录到 Bob 的网站并拥有一些机密数据。也许是公司内部网(只能通过 LAN 上的浏览器访问),或者她的网上银行(只能通过输入用户名和密码后获得的 cookie 访问)。
Alice 访问 Mallory 的网站,该网站包含一些 JavaScript,导致 Alice 的浏览器向 Bob 的网站发出 HTTP 请求(通过她的 IP 地址和 cookie 等)。这可以像使用 XMLHttpRequest 并读取 responseText.
XMLHttpRequest
responseText
浏览器的同源策略阻止 JavaScript 读取 Bob 网站返回的数据(Bob 和 Alice 不希望 Mallory 访问该网站)。 (请注意,例如,您可以跨源使用 元素显示图像,因为图像的内容不会暴露给 JavaScript(或 Mallory)……除非您将画布放入其中在这种情况下,您将生成同源违规错误)。
对于任何给定的 URL,可能不需要 SOP。这种情况的一些常见场景是:
…但是浏览器无法知道上述任一情况是否属实,因此信任不是自动的,并且应用了 SOP。在浏览器将从 Bob 收到的数据提供给其他网站之前,必须明确授予权限。
浏览器扩展*、浏览器开发人员工具中的“网络”选项卡以及 Postman 等应用程序都是已安装的软件。他们不会将数据从一个网站传递到属于另一网站的 JavaScript 只是因为您访问了该不同的网站。安装软件通常需要更有意识的选择。
*
不存在被视为风险的第三方(Mallory)。
##*# 浏览器扩展确实需要仔细编写以避免跨源问题。 请参阅 Chrome 文档作为示例.
# 浏览器扩展确实需要仔细编写以避免跨源问题。
元素来加载图像,那么它会显示在页面上,但向 Mallory 暴露的信息很少。 JavaScript 无法读取图像(除非您使用 crossOrigin 属性显式启用 CORS 请求权限),然后将其复制到她的服务器。
元素来加载图像,那么它会显示在页面上,但向 Mallory 暴露的信息很少。 JavaScript 无法读取图像(除非您使用
属性显式启用 CORS 请求权限),然后将其复制到她的服务器。
引用 Domenic Denicola(Google 的):
元素来显示图像)。 Mallory 的 JavaScript 不可能读取该资源中的数据,只有 Alice 的浏览器和 Bob 的服务器可以做到这一点,因此它仍然是安全的。
Access-Control-Allow-Origin HTTP response 标头是 CORS 标准的一部分,该标准允许 Bob 显式授予允许 Mallory 的网站通过 Alice 的浏览器访问数据。
HTTP
雷雷
… 只允许特定站点访问它,Bob 可以根据 Origin request 标头动态生成该标头,以允许多个(但不是全部)站点访问它.
Origin
Bob 如何设置响应标头的细节取决于 Bob 的 HTTP 服务器和/或服务器端编程语言。 Node.js/Express.js 的用户应该使用记录良好的 CORS 中间件。其他平台的用户应该看看这个 各种常见配置指南集 可能会有所帮助。
NB:有些请求很复杂,会发送一个 preflight OPTIONS 请求,服务器必须先响应该请求,然后浏览器才会发送 JS 想要发出的 GET/POST/PUT/Whatever 请求。仅将 Access-Control-Allow-Origin 添加到特定 URL 的 CORS 实现通常会因此而出错。
Access-Control-Allow-Origin
显然,只有在满足以下任一条件时,Bob 才会通过 CORS 授予权限:
这取决于你的服务器端环境。
如果可以的话,使用专门用于处理 CORS 的库,因为它们将为您提供简单的选项,而不必手动处理所有内容。
Enable-Cors.org 有一个针对特定平台和框架的文档列表,您可能会觉得有用。
Mallory 没有标准机制来添加此标头,因为它必须来自 Bob 的网站,而她无法控制该网站。
预检的.
enctype
在这些情况下,这个答案的其余部分仍然适用,但您还需要确保服务器可以侦听预检请求(这将是OPTIONS(而不是GET、POST 或您尝试发送的任何内容)并使用正确的 Access-Control-Allow-Origin 标头以及 进行响应Access-Control-Allow-Methods 和 Access-Control-Allow-Headers 允许您的特定 HTTP 方法或标头。
OPTIONS
GET
POST
进行响应Access-Control-Allow-Methods
Access-Control-Allow-Headers
有时人们在尝试构建 Ajax 请求时会犯错误,有时这些错误会触发预检的需要。如果 API 设计为允许跨源请求,但不需要任何需要预检的内容,那么这可能会中断访问。
触发此问题的常见错误包括:
Content-Type: application/json
Content-Type## 时) # 和
).
模式)
the fetch API(而不是XMLHttpRequest),那么您可以将其配置为不尝试使用CORS。
API
),那么您可以将其配置为不尝试使用CORS。
这不会让您执行任何需要 CORS 执行的操作。 您将无法阅读回复。您将无法提出需要预检的请求。
fetch 发出请求并且没有获得使用 CORS 查看响应的权限时,给出的 Chrome 错误消息解释了如何执行此操作: ###因此:###雷雷
发出请求并且没有获得使用 CORS 查看响应的权限时,给出的 Chrome 错误消息解释了如何执行此操作:
Bob 还可以使用类似 JSONP 的 hack 来提供数据,这就是 CORS 出现之前人们进行跨域 Ajax 的方式。
它的工作原理是以 JavaScript 程序的形式呈现数据,并将数据注入 Mallory 的页面。
它要求 Mallory 信任 Bob 不会提供恶意代码。
注意共同主题:提供数据的站点必须告诉浏览器第三方站点可以访问它发送到浏览器的数据。
由于 JSONP 的工作原理是附加一个 元素,以 JavaScript 程序的形式加载数据,该程序调用页面中已有的函数,因此尝试在 URL 上使用 JSONP 技术返回 JSON 将失败 — 通常会出现 CORB 错误 — 因为 JSON 不是 JavaScript。
如果 JS 运行的 HTML 文档和请求的 URL 位于同一源(共享相同的方案、主机名和端口),则同源策略默认授予权限。不需要 CORS。
Mallory could 使用服务器端代码来获取数据(然后她可以像往常一样通过 HTTP 将数据从服务器传递到 Alice 的浏览器)。
它会:
服务器端代码可以由第三方(例如 CORS Anywhere)编写和托管。请注意这对隐私的影响:第三方可以监控谁在其服务器上代理了什么。
Bob 不需要授予任何权限即可发生这种情况。
这里没有安全隐患,因为这只是 Mallory 和 Bob 之间的事情。 Bob 无法认为 Mallory 是 Alice,也无法向 Mallory 提供应在 Alice 和 Bob 之间保密的数据。
因此,Mallory 只能使用此技术来读取 public 数据。
但是请注意,从他人网站获取内容并自行展示可能会违反版权,并使您面临法律诉讼。
正如“为什么同源策略仅适用于网页中的 JavaScript”部分所述,您可以通过不在网页中编写 JavaScript 来避免 SOP。
这并不意味着您不能继续使用 JavaScript 和 HTML,但您可以使用其他一些机制来分发它,例如 Node-WebKit 或 PhoneGap。
浏览器扩展可以在应用同源策略之前在响应中注入 CORS 标头。
这些对于开发很有用,但对于生产站点来说并不实用(要求站点的每个用户安装禁用其浏览器安全功能的浏览器扩展是不合理的)。
它们也往往只适用于简单的请求(在处理预检选项请求时失败)。
拥有适当的开发环境和本地开发服务器 通常是更好的方法。
请注意,SOP / CORS 不能缓解需要独立处理的 XSS、CSRF 或 SQL 注入 攻击。
目标服务器必须允许跨域请求。为了通过express允许它,只需处理http选项请求:
tl;dr — 当您想要(主要)使用客户端 JS 从不同的服务器读取数据时,您需要包含数据的服务器向需要数据的代码授予显式权限。
最后有一个摘要,答案中有标题,以便更容易找到相关部分。不过,建议阅读所有内容,因为它为理解 why 提供了有用的背景,从而使了解 how 在不同情况下如何应用变得更容易。
关于同源政策
这是同源策略。它是浏览器实现的安全功能。
您的特殊情况显示了它是如何为 XMLHttpRequest 实现的(如果您使用 fetch,您将得到相同的结果),但它也适用于其他事物(例如加载到
或加载到
中的文档),只是实现略有不同。
演示 SOP 需求的标准场景可以用 三个字符:
来演示https://www.example.com/
)http://localhost:4300
)Alice 登录到 Bob 的网站并拥有一些机密数据。也许是公司内部网(只能通过 LAN 上的浏览器访问),或者她的网上银行(只能通过输入用户名和密码后获得的 cookie 访问)。
Alice 访问 Mallory 的网站,该网站包含一些 JavaScript,导致 Alice 的浏览器向 Bob 的网站发出 HTTP 请求(通过她的 IP 地址和 cookie 等)。这可以像使用
一样简单XMLHttpRequest
并读取responseText
.浏览器的同源策略阻止 JavaScript 读取 Bob 网站返回的数据(Bob 和 Alice 不希望 Mallory 访问该网站)。 (请注意,例如,您可以跨源使用
元素显示图像,因为图像的内容不会暴露给 JavaScript(或 Mallory)……除非您将画布放入其中在这种情况下,您将生成同源违规错误)。
为什么同源策略适用,而你认为它不应该
对于任何给定的 URL,可能不需要 SOP。这种情况的一些常见场景是:
…但是浏览器无法知道上述任一情况是否属实,因此信任不是自动的,并且应用了 SOP。在浏览器将从 Bob 收到的数据提供给其他网站之前,必须明确授予权限。
为什么同源策略适用于网页中的 JavaScript 而没有其他作用
网页之外
浏览器扩展
*
、浏览器开发人员工具中的“网络”选项卡以及 Postman 等应用程序都是已安装的软件。他们不会将数据从一个网站传递到属于另一网站的 JavaScript 只是因为您访问了该不同的网站。安装软件通常需要更有意识的选择。不存在被视为风险的第三方(Mallory)。
##*
网页内# 浏览器扩展确实需要仔细编写以避免跨源问题。
请参阅 Chrome 文档作为示例.
也就是说,有些信息确实泄露了,元素来加载图像,那么它会显示在页面上,但向 Mallory 暴露的信息很少。 JavaScript 无法读取图像(除非您使用
crossOrigin属性显式启用 CORS 请求权限),然后将其复制到她的服务器。
引用 Domenic Denicola(Google 的):
这就是为什么您需要 CORS 权限才能跨源加载字体。为什么用JS不用读取数据就能在页面显示数据
元素来显示图像)。 Mallory 的 JavaScript 不可能读取该资源中的数据,只有 Alice 的浏览器和 Bob 的服务器可以做到这一点,因此它仍然是安全的。
CORS
Access-Control-Allow-Origin
一个基本的实现只包括:HTTP
response 标头是 CORS 标准的一部分,该标准允许 Bob 显式授予允许 Mallory 的网站通过 Alice 的浏览器访问数据。雷雷
...在响应标头中以允许任何网站读取数据。雷雷
… 只允许特定站点访问它,Bob 可以根据
Origin
request 标头动态生成该标头,以允许多个(但不是全部)站点访问它.Bob 如何设置响应标头的细节取决于 Bob 的 HTTP 服务器和/或服务器端编程语言。 Node.js/Express.js 的用户应该使用记录良好的 CORS 中间件。其他平台的用户应该看看这个 各种常见配置指南集 可能会有所帮助。
NB:有些请求很复杂,会发送一个 preflight OPTIONS 请求,服务器必须先响应该请求,然后浏览器才会发送 JS 想要发出的 GET/POST/PUT/Whatever 请求。仅将
Access-Control-Allow-Origin
添加到特定 URL 的 CORS 实现通常会因此而出错。显然,只有在满足以下任一条件时,Bob 才会通过 CORS 授予权限:
如何添加这些标头?
这取决于你的服务器端环境。
如果可以的话,使用专门用于处理 CORS 的库,因为它们将为您提供简单的选项,而不必手动处理所有内容。
Enable-Cors.org 有一个针对特定平台和框架的文档列表,您可能会觉得有用。
但我不是鲍勃!
Mallory 没有标准机制来添加此标头,因为它必须来自 Bob 的网站,而她无法控制该网站。
如果 Bob 正在运行公共 API,则可能有一种机制可以打开 CORS(可能通过以某种方式格式化请求,或者在登录到 Bob 站点的开发人员门户站点后的配置选项)。但这必须是 Bob 实现的机制。 Mallory 可以阅读 Bob 网站上的文档以查看是否有可用的内容,或者她可以与 Bob 交谈并要求他实施 CORS。提及“预检响应”的错误消息
预检的.
当(粗略地说)您尝试发出跨域请求时会发生这种情况:enctype
或某些其他请求标头中使用的 Content-Type)。如果您正确执行了需要预检的操作
在这些情况下,这个答案的其余部分仍然适用,但您还需要确保服务器可以侦听预检请求(这将是
OPTIONS
(而不是GET
、POST
或您尝试发送的任何内容)并使用正确的Access-Control-Allow-Origin
标头以及进行响应Access-Control-Allow-Methods
和Access-Control-Allow-Headers
允许您的特定 HTTP 方法或标头。如果您错误地触发了预检
有时人们在尝试构建 Ajax 请求时会犯错误,有时这些错误会触发预检的需要。如果 API 设计为允许跨源请求,但不需要任何需要预检的内容,那么这可能会中断访问。
触发此问题的常见错误包括:
Access-Control-Allow-Origin
和其他 CORS 响应标头放在请求上。这些不属于请求,不做任何有用的事情(您可以授予自己权限的权限系统有什么意义?),并且只能出现在响应中。Content-Type: application/json
标头(通常当作者混淆Content-Type## 时) # 和
接受).
不透明响应(
no-cors
有时您需要发出 HTTP 请求,但不需要读取响应。例如如果您将日志消息发布到服务器进行记录。模式)
the fetch
请注意,API
(而不是XMLHttpRequest),那么您可以将其配置为不尝试使用CORS。
这不会让您执行任何需要 CORS 执行的操作。 您将无法阅读回复。您将无法提出需要预检的请求。
它会让您发出一个简单的请求,而不会看到响应,并且不会在开发者控制台中填充错误消息。fetch
发出请求并且没有获得使用 CORS 查看响应的权限时,给出的 Chrome 错误消息解释了如何执行此操作:
###因此:###雷雷CORS 的替代方案
JSONP
Bob 还可以使用类似 JSONP 的 hack 来提供数据,这就是 CORS 出现之前人们进行跨域 Ajax 的方式。
它的工作原理是以 JavaScript 程序的形式呈现数据,并将数据注入 Mallory 的页面。
它要求 Mallory 信任 Bob 不会提供恶意代码。
注意共同主题:提供数据的站点必须告诉浏览器第三方站点可以访问它发送到浏览器的数据。
由于 JSONP 的工作原理是附加一个
元素,以 JavaScript 程序的形式加载数据,该程序调用页面中已有的函数,因此尝试在 URL 上使用 JSONP 技术返回 JSON 将失败 — 通常会出现 CORB 错误 — 因为 JSON 不是 JavaScript。
将两个资源移动到一个源
如果 JS 运行的 HTML 文档和请求的 URL 位于同一源(共享相同的方案、主机名和端口),则同源策略默认授予权限。不需要 CORS。
代理
Mallory could 使用服务器端代码来获取数据(然后她可以像往常一样通过 HTTP 将数据从服务器传递到 Alice 的浏览器)。
它会:
服务器端代码可以由第三方(例如 CORS Anywhere)编写和托管。请注意这对隐私的影响:第三方可以监控谁在其服务器上代理了什么。
Bob 不需要授予任何权限即可发生这种情况。
这里没有安全隐患,因为这只是 Mallory 和 Bob 之间的事情。 Bob 无法认为 Mallory 是 Alice,也无法向 Mallory 提供应在 Alice 和 Bob 之间保密的数据。
因此,Mallory 只能使用此技术来读取 public 数据。
但是请注意,从他人网站获取内容并自行展示可能会违反版权,并使您面临法律诉讼。
编写网络应用程序以外的东西
正如“为什么同源策略仅适用于网页中的 JavaScript”部分所述,您可以通过不在网页中编写 JavaScript 来避免 SOP。
这并不意味着您不能继续使用 JavaScript 和 HTML,但您可以使用其他一些机制来分发它,例如 Node-WebKit 或 PhoneGap。
浏览器扩展
浏览器扩展可以在应用同源策略之前在响应中注入 CORS 标头。
这些对于开发很有用,但对于生产站点来说并不实用(要求站点的每个用户安装禁用其浏览器安全功能的浏览器扩展是不合理的)。
它们也往往只适用于简单的请求(在处理预检选项请求时失败)。
拥有适当的开发环境和本地开发服务器 通常是更好的方法。
其他安全风险
请注意,SOP / CORS 不能缓解需要独立处理的 XSS、CSRF 或 SQL 注入 攻击。
###概括###
your- 客户端代码中执行任何操作来启用 CORS 访问某人 else 的 服务器。
如果您控制服务器,则会发出请求:向其添加 CORS 权限。
- 如果您与控制它的人很友好:让他们为其添加 CORS 权限。
- 如果它是公共服务(请记住,
大多数第三方 API 都设计为仅通过服务器端代码进行交互,并且不支持 CORS- ,但对于支持 CORS 的 API 除外) :
阅读他们的 API 文档,看看他们是如何使用客户端 JavaScript 访问它的:
- 他们可能会告诉你使用特定的 URL
- 他们可能支持 JSONP 而不是 CORS
- 他们可能根本不支持客户端代码的跨源访问(这可能是出于安全考虑而故意做出的决定,特别是如果您必须在每个请求中传递个性化的 API 密钥)。
-
确保您没有触发不需要的预检请求。 API 可能会授予简单请求的权限,但不会授予预检请求的权限。
-
如果以上都不适用:让浏览器与 your- 服务器通信,然后让您的服务器从其他服务器获取数据并将其传递。 (还有第三方托管服务将 CORS 标头附加到您可以使用的可公开访问的资源)。