欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-02-16 09:11:12
什么是cors? 默认情况下,为预防某些而已行为,浏览器的xhr对象只能访问来源于同一个域中的资源。但是我们在日常实际开发中,常常会遇到跨域请求的需求,因此就出现了一...

什么是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

总结

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