跨站资源共享CORS原理深度解析
我相信如果你写过前后端分离的web应用程序,或者写过一些ajax请求调用,你可能会遇到过CORS错误。
- CORS是什么?
- 它与安全性有关吗?
- 为什么要有CORS?它解决了什么目的?
- CORS是怎样运行的?
如果您有这些问题,那么这篇文章非常适合您。
一、什么是CORS?
要了解什么是CORS(Cross-Origin Resource Sharing:跨站资源共享),首先我们需要了解什么是同源策略Same Origin Policy
(SOP)。SOP是所有的现代浏览器都具备的安全措施,它不允许从一个加载的js脚本和资源的Origin域与另一个Origin域进行交互。换句话说,如果您的网站是www.example.com
,则您无法向www.test.com
发出XHR请求。
那么SOP有什么用?如果没有同源策略的限制,你想想会发生什么? 比如:您已经登录到微博,并且不小心打开了一个恶意网站。该网站可以向微博发出请求,并从您微博登录的会话中提取个人信息。这显然是巨大的安全问题,为了防止这种情况,在浏览器中实施同源策略的限制。实际上,服务器并没有意识到在浏览器端发生的这一切,您仍然可以使用curl或postman发出相同的请求,并且一切响应正常,因为这些工具上没有SOP。
如果说SOP是限制跨源访问的一种方式,那么CORS是一种绕过SOP限制并允许您的前端向服务器提出合法请求的方法。 如果您的服务端的确是存在跨域的情况(实际上对于现代分布式应用,这很常见),由于SOP限制您的客户端将无法向多节点跨域服务器发出xhr请求。救星就出现了,CORS使我们能够以安全且可管理的方式做到跨域请求,突破同源策略的限制。
二、同源策略的源(Same Origin Policy的Origin)
源由三部分组成:协议,hostip(域)和端口。例如
http://example.com/xxx/index.html
和http://example.com/yyy/index.html
是同源,http://example.com:80
和http://example.com
(对于http默认端口为80)是同源。- 由于协议不同,
http://example.com/app1
和https://example.com/app2
是不同的源。 http://example.com
,http://www.example.com
由于域名不同,也是不同的源- 非常要注意的是
http://localhost
和http://127.0.0.1
是不同的源
同源策略就是:不允许不同的ip、端口、协议的应用在浏览器内进行互相资源共享、请求调用。
三、CORS如何运作?
CORS规范允许服务器向浏览器返回一些HTTP Headers,浏览器可以基于这些HTTP Headers来决定是否突破SOP的限制。最主要的一个HTTP Headers是Access-Control-Allow-Origin。
//目标服务允许所有的网站对其进行跨域访问
Access-Control-Allow-Origin: *
//目标服务允许特定的网站对其进行跨域访问
Access-Control-Allow-Origin: https://example.com
CORS有两种类型的请求:“simple”简单请求和“preflight”预检请求,根据请求方法的不同由浏览器确定使用哪种请求。
simple简单请求:
如果符合以下所有条件,则API请求被视为简单请求:
- API方法是以下方法之一:GET,POST或HEAD。
Content-Type
请求头包含:application/x-www-form-urlencoded
,multipart/form-data
,text/plain
这两个条件将构成大多数简单请求的用例,但是可以在此处找到更详细的简单请求条件列表。
如果您的API请求被视为simple
简单请求,这个请求就可以直接被发送给服务器。服务器使用CORS HTTP Headers进行响应,浏览器将检查Access-Control-Allow-Origin
后决定这个请求是否可以突破同源策略的限制,进行下一步的处理。
preflight预检请求:
如果您的API请求不满足成为简单请求的标准(最常见不满足简单请求标准的Content-Type
值为application/json
),则浏览器将在发送实际请求之前发出预检请求。
举一个例子,我们尝试使用GET
请求https://example.com/status
,Content-Type
是application/json
,所以浏览器认为它不符合一个简单请求的标准,因此浏览器会在发出实际请求之前发出预检请求,这个预检请求是使用HTTP的 OPTIONS方法发出的:
curl --location --request OPTIONS 'http://example.com/status' \
--header 'Access-Control-Request-Method: GET' \
--header 'Access-Control-Request-Headers: Content-Type, Accept' \
--header 'Origin: http://test.com'
上面的curl就是模拟预检请求,实际作用是:浏览器希望告诉服务器,我的实际请求将使用HTTP GET
method进行调用,Content-Type
与Accept
作为HTTP headers,这个请求是从https://test.com
发起的。服务器响应此请求:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: OPTIONS, GET, HEAD, POST
Access-Control-Allow-Headers: Content-Type, Accept
Access-Control-Allow-Origin
:允许发出请求的源,或者*
可以从任何来源发出请求。(即允许跨域的源)Access-Control-Allow-Methods
:允许的以逗号分隔的HTTP方法列表。(即允许跨域的HTTP方法)Access-Control-Allow-Headers
:允许发送的HTTP headers列表。
浏览器收到服务端的预检请求响应之后,在我们的示例中服务器响应*
可以从任何来源发出请求,因此现在浏览器将再次访问https://example.com/status
,使用GET方法(不再是OPTIONS方法),浏览器将不再限制该请求的发出与响应数据的接收。
如果预检请求响应的Origin是特定的Access-Control-Allow-Origin: http://domain.com
,浏览器将出现Cross-Origin Request Blocked
错误。因为服务器端预检结果只允许http://domain.com
发出跨域请求,不允许其他应用向我发出跨域请求。
四、如何处理CORS错误
我们现在知道什么是CORS及其工作原理,后面的事情其实就简单了。从上面的内容我们需要注意的是,对CORS的完全控制权在服务器,即服务器可以允许或禁止源的跨域访问。所以说跨域问题的处理一般都在服务端进行,不同的服务端的处理HTTP 请求头的代码是不一样的,当然也可以不用写代码,比如:nginx、haproxy设置。但是万变不离其宗:最终都是对HTTP Headers进行重写。
我就简单的举几个例子:
比如Servlet处理跨域
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
response.setHeader("Access-Control-Allow-Origin", "*"); //解决跨域访问报错
response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
chain.doFilter(req, resp);
}
比如Spring MVC配置
@Configuration
public class GlobalCorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") //添加映射路径,“/**”表示对所有的路径实行全局跨域访问权限的设置
.allowedOrigins("*") //开放哪些ip、端口、域名的访问权限
.allowCredentials(true) //是否允许发送Cookie信息
.allowedMethods("GET","POST", "PUT", "DELETE") //开放哪些Http方法,允许跨域访问
.allowedHeaders("*") //允许HTTP请求中的携带哪些Header信息
.exposedHeaders("*"); //暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)
}
};
}
}
欢迎关注我的博客,里面有很多精品合集
- 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
- 《VUE深入浅出系列》
跨站资源共享CORS原理深度解析的更多相关文章
- CORS(跨站资源共享)介绍
起因 有同学在nginx站点配置中加了一行Access-Control-Allow-Origin *,导致微信中业务数据异常,抓包看http头有两个Access-Control-Allow-Origi ...
- SpringSecurity环境下配置CORS跨站资源共享规则
一.CORS简述 要说明CORS(Cross Origin Resourse-Sharing) 跨站资源共享,就必须先说同源策略.长话短说,同源策略就是向服务端发起请求的时候,以下三项必须与当前浏览器 ...
- 跨域资源共享CORS与JSONP
同源策略限制: 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果没有同源策略,攻击者可以通过JavaScript获取你的邮件以及其他敏感信息,比如说 ...
- 跨域解决方案 - 跨域资源共享cors
目录 1. cors 介绍 2. 原理 3. cors 解决跨域 4. 自定义HTTP 头部字段解决跨域 5. 代码演示 5. 参考链接 1. cors 介绍 cors 说的是一个机制,其实相当于一个 ...
- VUE SpringCloud 跨域资源共享 CORS 详解
VUE SpringCloud 跨域资源共享 CORS 详解 作者: 张艳涛 日期: 2020年7月28日 本篇文章主要参考:阮一峰的网络日志 » 首页 » 档案 --跨域资源共享 CORS 详解 ...
- 网络编程-跨域资源共享 CORS
目录 1.什么是同源策略? 2.跨域资源共享 CORS 3.预检请求 4.CORS相关字段 5.Golang实现跨域 6.参考资料 1.什么是同源策略? 如果两个 URL 的 protocol.por ...
- 跨域资源共享(CORS)问题解决方案
CORS:Cross-Origin Resource Sharing(跨域资源共享) CORS被浏览器支持的版本情况如下:Chrome 3+.IE 8+.Firefox 3.5+.Opera 12+. ...
- java8Stream原理深度解析
Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...
- mysql索引原理深度解析
mysql索引原理深度解析 一.总结 一句话总结: mysql索引是b+树,因为b+树在范围查找.节点查找等方面优化 hash索引,完全平衡二叉树,b树等 1.数据库中最常见的慢查询优化方式是什么? ...
随机推荐
- 最全总结 | 聊聊 Python 数据处理全家桶(Sqlite篇)
1. 前言 上篇文章 聊到 Python 处理 Mysql 数据库最常见的两种方式,本篇文章继续说另外一种比较常用的数据库:Sqlite Sqlite 是一种 嵌入式数据库,数据库就是一个文件,体积很 ...
- 用 Java 做个“你画手机猜”的小游戏
本文适合有 Java 基础的人群 作者:DJL-Lanking HelloGitHub 推出的<讲解开源项目>系列.有幸邀请到了亚马逊 + Apache 的工程师:Lanking( htt ...
- [0CTF 2016]piapiapia(反序列逃逸)
我尝试了几种payload,发现有两种情况. 第一种:Invalid user name 第二种:Invalid user name or password 第一步想到的是盲注或者报错,因为fuzz一 ...
- Android动画系列之帧动画和补间动画
原文首发于微信公众号:jzman-blog,欢迎关注交流! Android 提供三种动画:帧动画.补间动画和属性动画,本篇文章介绍帧动画以及补间动画的使用,属性动画的使用将在后面的文章中分享,那就来复 ...
- 什么是垃圾搜集(GC)?为什么要有GC呢?
GC的全称是Gabage Collection,翻译过来就是"垃圾收集"的意思.那么我们为什么用GC呢? 那么我们接下来就来聊一聊GC的创造背景.在C和C++那个年代的程序员界的长 ...
- Python-变量-数字类型
数字 number 整形 int 浮点型 float bool True(=1) False(=0) int_num = 10 float_num = 10.1 bool_True = True bo ...
- PCIE_DMA实例五:基于XILINX XDMA的PCIE高速采集卡
PCIE_DMA实例五:基于XILINX XDMA的PCIE高速采集卡 一:前言 这一年关于PCIE高速采集卡的业务量激增,究其原因,发现百度"xilinx pcie dma",出 ...
- 记录一下第一次写 50行 SQL代码
这 是一个电商项目,做的是报表的展示,我还以为要请求几次,结果,用一个SQL全部查完了 下面是目标效果图 这是我的SQL代码 SELECT product.NAME, product.price, p ...
- matlab中fspecial Create predefined 2-D filter以及中值滤波均值滤波以及高斯滤波
来源: 1.https://ww2.mathworks.cn/help/images/ref/fspecial.html?searchHighlight=fspecial&s_tid=doc_ ...
- 深入浅出学Java-HashMap
一.概要 HashMap在JDK1.8之前的实现方式 数组+链表,但是在JDK1.8后对HashMap进行了底层优化,改为了由 数组+链表+红黑树实现,主要的目的是提高查找效率. 如下图所示: JDK ...