专栏首页云前端[译] 理解 CORS

[译] 理解 CORS

原文: https://medium.com/@baphemot/understanding-cors-18ad6b478e2b

"OK, but no"

只要用过 AJAX,你应该就很熟悉浏览器控制台中出现的如下报错:

当你看到这个信息,就意味着响应失败了;但你依然能在浏览器开发工具的网络 tab 里看到返回数据 -- 这是什么情况呢?

跨域资源共享(CORS: Cross-Origin Resource Sharing)

你所观察到的这种行为是浏览器 CORS 实现机制的效果。在 CORS 成为标准之前,由于安全原因,没有办法跨域调用 API。也就是(一定程度上依旧是)被所谓同源策略(Same-Origin Policy)限制住了。

CORS 机制是为了在认可用户发起的请求的同时,阻止那些恶意 JS;并在以下情况发起的 HTTP 请求时被触发:

  • 一个不同的域(比如从 example.com 的站点调用 api.com)
  • 一个不同的子域(比如从 example.com 的站点调用 api.example.com)
  • 一个不同的端口(比如从 example.com 的站点调用 example.com:3001)
  • 一个不同的协议(比如从 https://example.com 的站点调用 http://example.com)

这种机制阻止了当你已经登录 www.yourbank.com 的情况下,攻击者在各种网站上植入的脚本(比如通过 Google Ads 显示的广告)向 www.yourbank.com 发起的携带 你的身份凭证 的 AJAX 请求。

对于“简单的” GET 或 POST 请求,如果服务器没有对其作出携带特殊 HTTP 头部的响应 -- 请求依然被发送并且数据也照样被返回,但浏览器将不允许 Javascript 访问该响应。

如果浏览器尝试着去弄一个“没那么简单”的请求(比如一个包含了 cookie 的请求,或 Content-type 不是 application/x-www-form-urlencodedmultipart/form-datatext-plain三者之一的),则被称为预检(preflight)的机制将被用到,并且一个 OPTIONS 请求会被发往服务器。

关于“没那么简单”的请求,一个常见的例子是在请求中加入 cookie 或自定义头部 -- 如果浏览器发送了这样的请求且服务器没有正确响应的话,则只有预检调用会发送(不包含额外的头部),而浏览器本应使用的真实的 HTTP 请求就不会被发送了。

那些 Access-Control-Allow-什么什么的...

在 CORS 请求和响应中,都用到了一些 HTTP 头部,其中以下这几个是你必须理解的:

Origin

该头部是客户端发起的请求的一部分,包含了应用所在的域。由于安全原因,浏览器不会允许用户重写这个值。

Access-Control-Allow-Credentials

该头部只需要在服务器支持通过 cookie 认证的情况下出现在响应中。这种情况下,其唯一合法值就是 true。

Access-Control-Allow-Methods

一个逗号分隔的、表示服务器将会支持的 HTTP 请求动词(如 GET, POST)列表。

Access-Control-Allow-Headers

格式为一个逗号分隔的列表,表示服务器将会支持的请求头部值。如果使用了自定义头部(比如 x-authentication-token),则应该将其置于这个 ACA 头部(译注:即 Access-Control-Allow-Headers)响应中,并返回到 OPTIONS 调用中;除非该请求被阻塞了。

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

Access-Control-Expose-Headers

相似的是,该响应应包含一个头部列表,表示将在实际的响应中出现的值,并应在客户端中有效。所有其他头部则会被限制。

Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header

如何搞定 CORS “错误” ?

首先要清楚的是,CORS 行为并非一种错误 -- 这种机制致力于保护你的用户、你本身,或你调用的站点。

有时,缺少合适的头部,会导致客户端的错误执行(如丢失了 API key 等认证信息)。

取决于你面临的场景,以下手段可以“搞定这种错误”:

A -- 我开发前端,也能控制后端,或者认识那个开发后端的哥们

这是最好的情况了 -- 你能根据调用,在服务器上实现合适的 CORS 响应。如果 API 用 node 的 express 实现,那么简单的使用 cors 包(译注:https://github.com/expressjs/cors)就可以了。如果要保证站点的适度安全,可以考虑为 Access-Control-Allow-Origin 设置一个白名单。

B -- 我开发前端,且暂时控制不了后端,我需要一个临时的办法

这是次优的情况,因为其实这就是手段 A,只是暂时性的受限。为了临时解决,可以让浏览器忽略 CORS 机制 -- 比如使用 ACAO Chrome 扩展(译注: 或指 Allow-Control-Allow-Origin: * 扩展) 或用如下参数在启动 Chrome 时完全禁止 CORS:

chrome --disable-web-security --user-data-dir

切记,这将禁止浏览器会话期间 所有 网站的 CORS 机制;要小心慎用。

另外的替代方法是使用 devServer.proxy(假设你用到了 webpack 做开发);或使用一个 CORS-as-a-service 解决方案,比如 https://cors-anywhere.herokuapp.com/ 。

C -- 我开发前端,并总是控制不了后端的

Ok,现在事儿大了。首先要搞清为什么服务器没有发送适当的头部。

也许是不允许第三方应用访问其 API ?又或者其 API 只服务于服务器端而非浏览器?要么就是你需要在 URL 中发送认证令牌?

如果你依然认为可以通过浏览器访问数据,就得在浏览器应用和 API 之间编写自己的代理了,就类似于我们在手段 B 中做的那样。

在中间加一个代理

该代理不必和你的应用运行在同样的域下,只要当代理本身和客户端通讯时正确支持 CORS 就行。代理和 API 之间的通讯就完全不必支持 CORS 了。

你既可以编写自己的平台,也可以使用诸如 https://www.npmjs.com/package/cors-anywhere 的成熟方案。

要记住如果你需要支持身份凭证,这样的办法会引入一个安全风险。

关于 CORS 的更多

如果希望学习更多关于 CORS 的细节,推荐阅览这篇 MDN 文章(https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)。

(end)

本文分享自微信公众号 - 云前端(fewelife),作者:lua

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-03-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [译] 使用 microbundle 打包 TypeScript 组件库

    原文:https://codewithhugo.com/microbundle-typescript-npm-module/

    江米小枣
  • [译] 精通 Intersection Observer API

    原文:https://www.hweaver.com/intersection-observer-single-page-navigation/

    江米小枣
  • 人人都能看懂的鸿蒙 “JS 小程序” 数据绑定原理

    在几天前开源的华为 HarmonyOS (鸿蒙)中,提供了一种“微信小程序”式的跨平台开发框架,通过 Toolkit 将应用代码编译打包成 JS Bundle,...

    江米小枣
  • 神秘方盒可破解任意iPhone,美国警察纷纷抢购这款破案神器

    自从2016年FBI求助苹果帮忙解锁恐怖分子的iPhone而惨遭拒绝之后,破解iPhone就已经不再只是黑客的目标,美国警察无不寻找各种破解iPhone的技术手...

    FB客服
  • NLP(4)——用词向量技术简单分析红楼梦人物关系用n-gramma生成词向量word2vect进行模型训练

    前言:出于种种原因,总是不自觉把爱好和工作相互结合起来,每每感叹于曹雪芹构思的巧妙,语言的精炼,情节的感人……于是蹦出想法,看机器能否读懂“宝黛”之间的爱情。

    DC童生
  • 根本停不下来!给它一个轮廓,TensorFlow还你一只完整的喵 (附论文下载)

    大数据文摘
  • SAP Fiori UI上关于时区Timezone的一些问题和解决方案

    先说问题,我创建了一个Lead,创建时间14:21, TimeZone is UTC+8.

    Jerry Wang
  • GitHub Star 过万,这款神器必须安利!

    今天跟大家推荐一款开源神器,用上后,保证绝对大幅度提升你的 GitHub 使用体验。

    GitHubDaily
  • 机房收费系统(VB.NET)个人版总结

    重构版个人机房收费系统大概从暑假开学开始进行,花了不到一个半月的时间才完成,下面对我在重构过程中的一写理解。

    令仔很忙
  • flume与logstash对比

    没找到这篇文章的原文 ? ? ? ?

    Albert陈凯

扫码关注云+社区

领取腾讯云代金券