你可能不知道的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 相关文章推荐
JavaScript 脚本将当地时间转换成其它时区
Mar 19 Javascript
JavaScript 对Cookie 操作的封装小结
Dec 31 Javascript
如何让easyui gridview 宽度自适应窗口改变及fitColumns应用
Jan 25 Javascript
将页面table内容与样式另存成excel文件的方法
Aug 05 Javascript
js生成随机数的方法实例
Oct 16 Javascript
新入门node.js必须要知道的概念(必看篇)
Aug 10 Javascript
react.js 翻页插件实例代码
Jan 19 Javascript
webpack中CommonsChunkPlugin详细教程(小结)
Nov 09 Javascript
Element-ui tree组件自定义节点使用方法代码详解
Sep 17 Javascript
使用js实现一个简单的滚动条过程解析
Sep 10 Javascript
node.js使用mongoose操作数据库实现购物车的增、删、改、查功能示例
Dec 23 Javascript
浅谈JavaScript窗体Window.ShowModalDialog使用
Jul 22 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中的 == 运算符进行字符串比较
2006/11/26 PHP
php学习之流程控制实现代码
2011/06/09 PHP
CI框架源码阅读,系统常量文件constants.php的配置
2013/02/28 PHP
PHP的cURL库简介及使用示例
2015/02/06 PHP
iframe自适应宽度、高度 ie6 7 8,firefox 3.86下测试通过
2010/07/29 Javascript
基于Jquery的回车成tab焦点切换效果代码(Enter To Tab )
2010/11/14 Javascript
多浏览器兼容性比较好的复制到剪贴板的js代码
2011/10/09 Javascript
在浏览器窗口上添加遮罩层的方法
2012/11/12 Javascript
使用按钮控制以何种方式打开新窗口的属性介绍
2012/12/17 Javascript
jquery实现可拖拽弹出层特效
2015/01/04 Javascript
JS实现仿腾讯微博无刷新删除微博效果代码
2015/10/16 Javascript
基于zepto.js简单实现上传图片
2016/06/21 Javascript
JS表格组件神器bootstrap table使用指南详解
2017/04/12 Javascript
JS传参及动态修改页面布局
2017/04/13 Javascript
vue2.0 移动端实现下拉刷新和上拉加载更多的示例
2018/04/23 Javascript
在小程序中使用腾讯视频插件播放教程视频的方法
2018/07/10 Javascript
详解webpack+ES6+Sass搭建多页面应用
2018/11/05 Javascript
Vue渲染过程浅析
2019/03/14 Javascript
Node.js一行代码实现静态文件服务器的方法步骤
2019/05/07 Javascript
Vue源码分析之Vue实例初始化详解
2019/08/25 Javascript
Vue实现数据请求拦截
2019/10/23 Javascript
pandas中的DataFrame按指定顺序输出所有列的方法
2018/04/10 Python
python操作日志的封装方法(两种方法)
2019/05/23 Python
django框架使用views.py的函数对表进行增删改查内容操作详解【models.py中表的创建、views.py中函数的使用,基于对象的跨表查询】
2019/12/12 Python
HTML5 Convas APIs方法详解
2015/04/24 HTML / CSS
Woolworth官网:澳洲第一大超市
2017/06/25 全球购物
Priority Pass机场贵宾室会籍计划:全球超过1200间机场贵宾室
2018/08/26 全球购物
Godiva巧克力英国官网:比利时歌帝梵巧克力
2018/08/28 全球购物
iKRIX意大利网上商店:男女豪华服装和配件
2019/10/09 全球购物
EJB3.1都有哪些改进
2012/11/17 面试题
审计工作个人的自我评价
2013/12/25 职场文书
优秀教师的感人事迹
2014/02/04 职场文书
美德少年事迹材料500字
2014/08/19 职场文书
我们的节日中秋节活动总结
2015/03/23 职场文书
《你在为谁工作》心得体会(共8篇)
2016/01/20 职场文书
关于公司年会的开幕词
2016/03/04 职场文书