跨域资源共享 CORS - vue3 项目实战
跨域资源共享 CORS
前后端分离,难免会碰到跨域问题。跨域资源共享(CORS)是一种浏览器机制,可以对位于给定域之外的资源进行受控访问。它扩展并增加了同源策略(SOP)的灵活性。但是,如果网站的 CORS 策略配置和实施不当,它也会为基于跨域的攻击提供可能性。
同源策略
浏览器同源策略
(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
"同源"指的是"三个相同"。
- protocol 协议相同
- host 域名相同
- port 端口相同
举例来说,http://www.example.com/dir/page.html这个网址
- 协议是http://
- 域名是www.example.com
- 端口是80(默认端口可以省略)
跨域资源共享
CORS (Cross-Origin Resource Sharing,跨域资源共享)是一个协议,它由一系列传输的 HTTP头组成,这些 HTTP头决定浏览器是否阻止前端 JavaScript 代码获取跨域请求的响应。同源安全策略,默认阻止“跨域”获取资源。但是 CORS 给了web服务器这样的权限,即服务器可以选择,允许跨域请求访问到它们的资源。
出于安全性,浏览器限制脚本内发起的跨源 HTTP 请求。例如,XMLHttpRequest和Fetch API 遵循同源策略。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源。除非被请求的服务器的响应报文(HTTP Response header)包含了正确 CORS 响应头。
跨源资源共享(Cross-Origin Resource Sharing,简写 CORS)。一个正在运行的 web 应用,通过HTTP Response header来告诉浏览器,来自不同源的访问请求,是被允许的。是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它 origin(域,协议和端口),使得浏览器允许这些 origin,访问加载自己的资源。跨源资源共享,还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。
跨源域资源共享(CORS)机制允许 Web 应用服务器进行跨源访问控制,从而使跨源数据传输得以安全进行。现代浏览器支持在 API 容器中(例如 XMLHttpRequest 或 Fetch)使用 CORS,以降低跨源 HTTP 请求所带来的风险。
这份 CORS 允许在下列场景中使用跨站点 HTTP 请求:
- 由XMLHttpRequest或Fetch API发起的跨源 HTTP 请求。
- Web 字体(CSS 中通过@font-face 使用跨源字体资源),因此,网站就可以发布 TrueType 字体资源,并只允许已授权网站进行跨站调用。
- WebGL 贴图。使用 drawImage 将 Images/video 画面绘制到 canvas。
- 来自图像的 CSS 图形
CORS 头
跨源资源共享标准(CORS)新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP认证相关数据)。
CORS 请求失败会产生错误,但是为了安全,在 JavaScript 代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。
- Access-Control-Allow-Origin:指示请求的资源能共享给哪些域。
- Access-Control-Allow-Credentials:指示当请求的凭证标记为 true 时,是否响应该请求。
- Access-Control-Allow-Headers:用在对预请求的响应中,指示实际的请求中可以使用哪些 HTTP 头。
- Access-Control-Allow-Methods:指定对预请求的响应中,哪些 HTTP 方法允许访问请求的资源。
- Access-Control-Expose-Headers:指示哪些 HTTP 头的名称能在响应中列出。
- Access-Control-Max-Age:指示预请求的结果能被缓存多久。
- Access-Control-Request-Headers:用于发起一个预请求,告知服务器正式请求会使用那些 HTTP 头。
- Access-Control-Request-Method:用于发起一个预请求,告知服务器正式请求会使用哪一种 HTTP 请求方法。
- Origin:指示获取资源的请求是从什么域发起的。
CORS 请求
根据跨域资源共享机制的工作原理,可以划分为简单请求和非简单请求。主要应用于三个场景:简单请求、预检请求、认证请求
简单请求
某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch CORS 规范,而是XMLHttpRequest CORS 规范。若请求满足所有下述条件,则该请求可视为“简单请求”,有五个方面:
- 请求方法,使用下列方法之一:
GET
、POST
、HEAD
。 - 请求 header 中,仅包含【允许人为设置值】的首部字段。也就是说,不得人为设置下列集合之外的其他首部字段:
Accept
、Accept-Language
、Content-Language
、Content-Type
(需要注意额外的限制)。若浏览器使用的代理设置,浏览器的代理自动设置的首部字段(例如 Connection,User-Agent),是被允许的,也属于简单请求。另外,不能包含【自定义的首部字段】。比如:header 请求中,包含个人自定义首部字段X-PINGOTHER,此请求会被试为【非简单请求】。 Content-Type
的值仅限于下列三者之一:text/plain
、multipart/form-data
、application/x-www-form-urlencoded
。- 请求中的任意
XMLHttpRequest
对象均没有注册任何事件监听器;XMLHttpRequest 对象可以使用 XMLHttpRequest.upload 属性访问。 - 请求中没有使用
ReadableStream
对象。
Safari 浏览器
浏览器Safari,广泛应用于 iPhone,iPad 和 Mac 设备。苹果公司推出的新版浏览器:Safari Technology Preview。另外,WebKit Nightly是Safari遗弃版本,适用于 windows 上的版本,现在已经放弃了。曾经有过短暂的存在。
浏览器Safari Technology Preview和WebKit Nightly,为首部字段Accept
、Accept-Language
、Content-Language
的值有额外的限制。如果这些首部字段的值并不符合这些限制,这两款浏览器将这些请求视为非简单请求,也会发送预请求。参考内容如下:
- Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language
- Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS
- Switch to a blacklist model for restricted Accept headers in simple CORS requests
这两个版本的 Safari 浏览器的这些限制,不是CORS
的标准规范,不属于CORS
规范的一部分。
预检请求
凡是不能同时满足【简单请求】五个条件的,都被视为【非简单请求】,在发送正式请求之前,会首先使用OPTIONS方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。【预检请求】的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。
比如:网络请求 Axios 软件工具,与服务器交互信息,使用JSON方式的时候,其 header 头部请求是Content-Type:application/json。所以属于【非简单请求】,会发送【预检请求】。另外,当 header 头部请求信息中,携带 token 进行 http 验证的时候,其携带字段Authorization,此字段虽然不是个人自定义的,但却在【允许人为设置值】的首部字段范围之外,所以也是属于【非简单请求】,而发送【预检请求】。
举例:一个需要执行预检请求的 HTTP 请求。
const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://bar.other/resources/post-here/'); xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); xhr.setRequestHeader('Content-Type', 'application/xml'); xhr.onreadystatechange = handler; xhr.send('Arun');
上面的代码使用 POST 请求发送一个 XML 文档,该请求包含了一个自定义的请求首部字段(X-PINGOTHER: pingpong)。另外,该请求的 Content-Type 为 application/xml。因此,该请求需要首先发起【预检请求】。
Content-Type 请求类型列表,参考
认证请求
一般而言,对于跨源 XMLHttpRequest 或 Fetch 请求,浏览器不会发送身份凭证信息。服务器的响应头设置为:Access-Control-Allow-Credentials: false
。此时,Access-Control-Allow-Origin
,可以设置为 ,来允许任何的源请求。当然也可以设置为某个指定的域请求。例如:Access-Control-Allow-Origin: https://foo.example
,限制只有 https://foo.example 可以跨域访问而获得资源。
鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com
图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!