你可能不知道的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 相关文章推荐
最近项目写了一些js,水平有待提高
Jan 31 Javascript
Js 本页面传值实现代码
May 17 Javascript
深入理解JavaScript系列(14) 作用域链介绍(Scope Chain)
Apr 12 Javascript
js原型链原理看图说明
Jul 07 Javascript
Jquery操作下拉框(DropDownList)实现取值赋值
Aug 13 Javascript
a标签的href与onclick事件的区别详解
Nov 12 Javascript
jquery ztree实现树的搜索功能
Feb 25 Javascript
JavaScript中捕获/阻止捕获、冒泡/阻止冒泡方法
Dec 07 Javascript
JS获取鼠标位置距浏览器窗口距离的方法示例
Apr 11 Javascript
详解vue-router 路由元信息
Sep 13 Javascript
Vue中v-show添加表达式的问题(判断是否显示)
Mar 26 Javascript
js实现图片粘贴到网页
Dec 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递归使用示例(php递归函数)
2014/02/14 PHP
PHP+MySQL插入操作实例
2015/01/21 PHP
thinkPHP3.x常量整理(预定义常量/路径常量/系统常量)
2016/05/20 PHP
thinkPHP中验证码的简单实现方法
2016/12/05 PHP
PHP十六进制颜色随机生成器功能示例
2017/07/24 PHP
TinyMCE 新增本地图片上传功能
2010/11/05 Javascript
Javascript中的window.event.keyCode使用介绍
2011/04/26 Javascript
jquery内置验证(validate)使用方法示例(表单验证)
2013/12/04 Javascript
jQuery实现多按钮单击变色
2014/11/27 Javascript
JS+CSS实现电子商务网站导航模板效果代码
2015/09/10 Javascript
jquery+正则实现统一的表单验证
2015/09/20 Javascript
js实现新年倒计时效果
2015/12/10 Javascript
jQuery Html控件基本操作(日常收集整理)
2016/03/11 Javascript
禁用backspace网页回退功能的实现代码
2016/11/15 Javascript
jQuery判断邮箱格式对错实例代码讲解
2017/04/12 jQuery
Jquery-data的三种用法
2017/04/18 jQuery
ES6中字符串string常用的新增方法小结
2017/11/07 Javascript
vue axios基于常见业务场景的二次封装的实现
2018/09/21 Javascript
python时间整形转标准格式的示例分享
2014/02/14 Python
Python3.2中的字符串函数学习总结
2015/04/23 Python
Python爬虫_城市公交、地铁站点和线路数据采集实例
2018/01/10 Python
Ubuntu下升级 python3.7.1流程备忘(推荐)
2018/12/10 Python
python项目对接钉钉SDK的实现
2019/07/15 Python
python实现数据清洗(缺失值与异常值处理)
2019/12/02 Python
Python通过4种方式实现进程数据通信
2020/03/12 Python
幸福家庭事迹材料
2014/02/03 职场文书
大学学习计划书范文
2014/05/02 职场文书
体育教育毕业生自荐信
2014/06/29 职场文书
公司总经理岗位职责
2015/04/01 职场文书
紧急通知
2015/04/17 职场文书
2015年感恩父亲节活动策划方案
2015/05/05 职场文书
纪检部部长竞选稿
2015/11/21 职场文书
Python离线安装openpyxl模块的步骤
2021/03/30 Python
React列表栏及购物车组件使用详解
2021/06/28 Javascript
MySQL学习必备条件查询数据
2022/03/25 MySQL
Nginx反向代理、重定向
2022/04/13 Servers