你可能不知道的CORS跨域资源共享


Posted in Javascript onMarch 13, 2019

什么是CORS?

默认情况下,为预防某些而已行为,浏览器的XHR对象只能访问来源于同一个域中的资源。但是我们在日常实际开发中,常常会遇到跨域请求的需求,因此就出现了一种跨域请求的方案:CORS(Cross-Origin Resource Sharing)跨域资源共享。

CORS背后的原理是:使用自定的HTTP头部与服务器进行沟通,从而由服务器决定响应是否成功。

了解下同源策略

  • 源(origin)*:就是协议、域名和端口号;
  • 同源: 就是源相同,即协议、域名和端口完全相同;
  • 同源策略:同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源;
  • 同源策略的分类:
    • DOM 同源策略:即针对于DOM,禁止对不同源页面的DOM进行操作;如不同域名的 iframe 是限制互相访问。
    • XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
  • 不受同源策略限制:
    • 页面中的链接,重定向以及表单提交(因为表单提交,数据提交到action域后,本身页面就和其没有关系了,不会管请求结果,后面操作都交给了action里面的域)是不会受到同源策略限制的。
    • 资源的引入不受限制,但是js不能读写加载的内容:如嵌入到页面中的<script src="..."></script>,<img>,<link>,<iframe>等

为什么要跨域限制

  • 如果没有 DOM 同源策略:那么就没有啥xss的研究了,因为你的网站将不是你的网站,而是大家的,谁都可以写个代码操作你的网站界面
  • 如果没有XMLHttpRequest 同源策略,那么就可以很轻易的进行CSRF(跨站请求伪造)攻击:
    • 用户登录了自己的网站页面 a.com,cookie中添加了用户标识。
    • 用户浏览了恶意页面 b.com,执行了页面中的恶意 AJAX 请求代码。
    • b.com 向 a.com发起 AJAX HTTP 请求,请求会默认把 a.com对应cookie也同时发送过去。
    • a.com从发送的 cookie 中提取用户标识,验证用户无误,response 中返回请求数据;数据就泄露了。而且由于Ajax在后台执行,这一过程用户是无法感知的。
  • (附)有了XMLHttpRequest 同源策略就可以限制CSRF攻击?别忘了还有不受同源策略的:表单提交和资源引入,(安全问题下期在研究)

跨域决解方案

  • JSONP 跨域:借鉴于 script 标签不受浏览器同源策略的影响,允许跨域引用资源;因此可以通过动态创建 script 标签,然后利用 src 属性进行跨域;
    • 缺点:
    • 所有网站都可以拿到数据,存在安全性问题,需要网站双方商议基础token的身份验证。
    • 只能是GET,不能POST。
    • 可能被注入恶意代码,篡改页面内容,可以采用字符串过滤来规避此问题。
  • 服务器代理:浏览器有跨域限制,但是服务器不存在跨域问题,所以可以由服务器请求所要域的资源再返回给客户端。
  • document.domain、window.name 、location.hash:借助于iframe决解DOM同源策略
  • postMessage:决解DOM同源策略,新方案
  • CORS(跨域资源共享):这里讲的重点

CORS(跨域资源共享)

  • HTML5 提供的标准跨域解决方案,是一个由浏览器共同遵循的一套控制策略,通过HTTP的Header来进行交互;主要通过后端来设置CORS配置项。

CORS简单使用

之前说得CORS跨域,嗯嗯,后端设置Access-Control-Allow-Origin:*|[或具体的域名]就好了;

第一次尝试:

app.use(async(ctx,next) => {
 ctx.set({
 "Access-Control-Allow-Origin": "http://localhost:8088"
})

发现有些请求可以成功,但是有些还是会报错:

你可能不知道的CORS跨域资源共享

请求被同源策略阻止,预请求的响应没有通过检查:http返回的不是ok?

并且发现发送的是OPTIONS请求:

你可能不知道的CORS跨域资源共享

发现:CORS规范将请求分为两种类型,一种是简单请求,另外一种是带预检的非简单请求

简单请求和非简单请求

浏览器发送跨域请求判断方式:

  • 浏览器在发送跨域请求的时候,会先判断下是简单请求还是非简单请求,如果是简单请求,就先执行服务端程序,然后浏览器才会判断是否跨域;
  • 而对于非简单请求,浏览器会在发送实际请求之前先发送一个OPTIONS的HTTP请求来判断服务器是否能接受该跨域请求;如果不能接受的话,浏览器会直接阻止接下来实际请求的发生。

什么是简单请求

1、请求方法是如下之一:

  • GET
  • HEAD
  • POST

2、所有的Header都只包含如下列表中(没有自定义header):

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

除此之外都是非简单请求

CORS非简单请求配置须知

正如上图报错显示,对于非简单请求,浏览器会先发送options预检,预检通过后才会发送真是的请求;

发送options预检请求将关于接下来的真实请求的信息给服务器:

Origin:请求的源域信息
Access-Control-Request-Method:接下来的请求类型,如POST、GET等
Access-Control-Request-Headers:接下来的请求中包含的用户显式设置的Header列表

服务器端收到请求之后,会根据附带的信息来判断是否允许该跨域请求,通过Header返回信息:

Access-Control-Allow-Origin:允许跨域的Origin列表
Access-Control-Allow-Methods:允许跨域的方法列表
Access-Control-Allow-Headers:允许跨域的Header列表,防止遗漏Header,因此建议没有特殊需求的情况下设置为*
Access-Control-Expose-Headers:允许暴露给JavaScript代码的Header列表
Access-Control-Max-Age:最大的浏览器预检请求缓存时间,单位为s

CORS完整配置

koa配置CORS跨域资源共享中间件:

const cors = (origin) => {
 return async (ctx, next) => {
  ctx.set({
   "Access-Control-Allow-Origin": origin, //允许的源
  })
  // 预检请求
  if (ctx.request.method == "OPTIONS") {
   ctx.set({
    'Access-Control-Allow-Methods': 'OPTIONS,HEAD,DELETE,GET,PUT,POST', //支持跨域的方法
    'Access-Control-Allow-Headers': '*', //允许的头
    'Access-Control-Max-Age':10000, // 预检请求缓存时间
    // 如果服务器设置Access-Control-Allow-Credentials为true,那么就不能再设置Access-Control-Allow-Origin为*,必须用具体的域名
    'Access-Control-Allow-Credentials':true // 跨域请求携带身份信息(Credential,例如Cookie或者HTTP认证信息)
   });
   ctx.send(null, '预检请求')
  } else {
   // 真实请求
   await next()
  }
 }
}

export default cors

现在不管是简单请求还是非简单请求都可以跨域访问啦~

跨域时如何处理cookie

cookie:

  • 我们知道http时无状态的,所以在维持用户状态时,我们一般会使用cookie;
  • cookie每次同源请求都会携带;但是跨域时cookie是不会进行携带发送的;

问题:

  • 由于cookie对于不同源是不能进行操作的;这就导致,服务器无法进行cookie设置,浏览器也没法携带给服务器(场景:用户登录进行登录操作后,发现响应中有set-cookie但是,浏览器cookie并没有相应的cookie)

决解:

  • 浏览器请求设置withCredentials为true即可让该跨域请求携带 Cookie;使用axios配置axios.defaults.withCredentials = true
  • 服务器设置Access-Control-Allow-Credentials=true允许跨域请求携带 Cookie

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
jQuery对表单元素的取值和赋值操作代码
May 19 Javascript
将文本输入框内容加入表中的js代码
Aug 18 Javascript
快速解决jQuery与其他库冲突的方法介绍
Jan 02 Javascript
jquery选择checked在ie8普通模式下的问题
Feb 12 Javascript
详解AngularJS中的表达式使用
Jun 16 Javascript
微信公众平台开发教程(六)获取个性二维码的实例
Dec 02 Javascript
用jQuery.ajaxSetup实现对请求和响应数据的过滤
Dec 20 Javascript
jquery实现左右滑动式轮播图
Mar 02 Javascript
利用Node.js了解与测量HTTP所花费的时间详解
Sep 22 Javascript
node前端模板引擎Jade之标签的基本写法
May 11 Javascript
浅谈webpack性能榨汁机(打包速度优化)
Jan 09 Javascript
vue-cli脚手架打包静态资源请求出错的原因与解决
Jun 06 Javascript
react项目如何使用iconfont的方法步骤
Mar 13 #Javascript
使用jquery的cookie实现登录页记住用户名和密码的方法
Mar 13 #jQuery
深入Node TCP模块的理解
Mar 13 #Javascript
详解如何使用微信小程序云函数发送短信验证码
Mar 13 #Javascript
vue计算属性computed的使用方法示例
Mar 13 #Javascript
vue防止花括号{{}}闪烁v-text和v-html、v-cloak用法示例
Mar 13 #Javascript
vue生命周期与钩子函数简单示例
Mar 13 #Javascript
You might like
php判断正常访问和外部访问的示例
2014/02/10 PHP
[原创]php简单防盗链验证实现方法
2016/07/09 PHP
Prototype Function对象 学习
2009/07/12 Javascript
innerhtml用法 innertext用法 以及innerHTML与innertext的区别
2009/10/26 Javascript
JS date对象的减法处理实现代码
2010/12/28 Javascript
js 针对html DOM元素操作等经验累积
2014/03/11 Javascript
jQuery 复合选择器应用的几个例子
2014/09/11 Javascript
javascript实现依次输入input自动定焦
2014/12/23 Javascript
PhotoShop给图片自动添加边框及EXIF信息的JS脚本
2015/02/15 Javascript
Jquery幻灯片特效代码分享--鼠标点击按钮时切换(1)
2015/08/15 Javascript
JS实现简单的tab切换选项卡效果
2016/09/21 Javascript
一篇文章搞定JavaScript类型转换(面试常见)
2017/01/21 Javascript
jQuery实现的简单获取索引功能示例
2018/06/04 jQuery
详解swiper在vue中的应用(以3.0为例)
2018/09/20 Javascript
对angularJs中controller控制器scope父子集作用域的实例讲解
2018/10/08 Javascript
关于Node.js中频繁修改代码重启服务器的问题
2020/10/15 Javascript
WebStorm中如何将自己的代码上传到github示例详解
2020/10/28 Javascript
[02:26]DOTA2英雄米拉娜基础教程
2013/11/25 DOTA
python控制台英汉汉英电子词典
2020/04/23 Python
python中使用百度音乐搜索的api下载指定歌曲的lrc歌词
2014/07/18 Python
Python中使用语句导入模块或包的机制研究
2015/03/30 Python
K-近邻算法的python实现代码分享
2017/12/09 Python
10 行 Python 代码教你自动发送短信(不想回复工作邮件妙招)
2018/10/11 Python
Python 旋转打印各种矩形的方法
2019/07/09 Python
如何给Python代码进行加密
2020/01/10 Python
Python实现队列的方法示例小结【数组,链表】
2020/02/22 Python
Python连接mysql方法及常用参数
2020/09/01 Python
英语自我介绍演讲稿
2014/09/01 职场文书
三人合伙协议书范本
2014/10/29 职场文书
督导岗位职责
2015/02/04 职场文书
2015个人简历自我评价语
2015/03/11 职场文书
房地产公司财务总监岗位职责
2015/04/03 职场文书
2015年乡镇流动人口工作总结
2015/05/12 职场文书
2016年4月份红领巾广播稿
2015/12/21 职场文书
人为什么会“幸灾乐祸”?
2019/08/06 职场文书
使用vue判断当前环境是安卓还是IOS
2022/04/12 Vue.js