你可能不知道的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 instanceof 与typeof使用说明
Jan 11 Javascript
jQuery替换textarea中换行的方法
Jun 10 Javascript
js获取及修改网页背景色和字体色的方法
Dec 29 Javascript
Highcharts 多个Y轴动态刷新数据的实现代码
May 28 Javascript
AngularJS ng-controller 指令简单实例
Aug 01 Javascript
Bootstrap基本布局实现方法详解
Nov 25 Javascript
JavaScript 日期时间选择器一些小结
Apr 02 Javascript
vue 2.1.3 实时显示当前时间,每秒更新的方法
Sep 16 Javascript
BootStrap table实现表格行拖拽效果
Dec 01 Javascript
bootstrap下拉分页样式 带跳转页码
Dec 29 Javascript
vscode中Vue别名路径提示的实现
Jul 31 Javascript
让JavaScript代码更加精简的方法技巧
Jun 01 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
跟我学Laravel之路由
2014/10/15 PHP
PHP发送AT指令实例代码
2016/05/26 PHP
LNMP部署laravel以及xhprof安装使用教程
2017/09/14 PHP
PHP使用Http Post请求发送Json对象数据代码解析
2020/07/16 PHP
如何实现浏览器上的右键菜单
2006/07/10 Javascript
File文件控件,选中文件(图片,flash,视频)即立即预览显示
2009/04/09 Javascript
JS window.opener返回父页面的应用
2009/10/24 Javascript
Js 随机数产生6位数字
2010/05/13 Javascript
JavaScript中的排序算法代码
2011/02/22 Javascript
jquery 无限级下拉菜单的简单实现代码
2014/02/21 Javascript
js+jquery常用知识点汇总
2015/03/03 Javascript
javascript中return,return true,return false三者的用法及区别
2015/11/17 Javascript
基于JavaScript实现轮播图代码
2016/07/14 Javascript
jQuery tagsinput在h5邮件客户端中应用详解
2016/09/26 Javascript
原生js仿淘宝网商品放大镜效果
2017/02/28 Javascript
angularjs $http实现form表单提交示例
2017/06/09 Javascript
动态Axios的配置步骤详解
2018/01/12 Javascript
vue 父组件调用子组件方法及事件
2018/03/29 Javascript
layui表格内放置图片,并点击放大的实例
2019/09/10 Javascript
javscript 数组扁平化的实现
2020/02/03 Javascript
[54:17]DOTA2-DPC中国联赛定级赛 RNG vs iG BO3第二场 1月10日
2021/03/11 DOTA
Django添加sitemap的方法示例
2018/08/06 Python
Python OpenCV图像指定区域裁剪的实现
2019/10/30 Python
完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
2020/04/01 Python
使用pandas库对csv文件进行筛选保存
2020/05/25 Python
Python web如何在IIS发布应用过程解析
2020/05/27 Python
CSS3字体效果的设置方法小结
2016/06/13 HTML / CSS
JDO的含义
2012/11/17 面试题
医学生求职自荐信
2013/10/25 职场文书
办加油卡单位介绍信
2014/01/09 职场文书
作风建设剖析材料
2014/10/06 职场文书
群众路线剖析材料怎么写
2014/10/09 职场文书
模范班主任事迹材料
2014/12/17 职场文书
2014年底个人工作总结
2015/03/10 职场文书
Django中的JWT身份验证的实现
2021/05/07 Python
基于Python实现nc批量转tif格式
2022/08/14 Python