跨域问题及其解决方案

197 阅读3分钟

同源策略及跨域问题

同源策略是浏览器的一套安全机制,当一个源的文档和脚本,与另一个源的资源进行通信时,同源策略就会对这个通信进行不同程度的限制。

对同源进行放行,对异源进行限制。

同源和异源

源(origin)= 协议 + 域名 + 端口

跨域出现的场景

  • 网络通信:a元素跳转,加载css,js,图片,ajax请求等。
  • JSAPI:window.open(),window.parent()等。
  • 存储:webStorage,indexDB等。

网络中的跨域

当浏览器加载页面后,会发出很多请求,比如:css,js,图片,ajax等。

发出请求页面称为页面源,请求目标称为目标源。当页面源和请求源一致时,称为同源,否则为异源。

浏览器如何限制异源请求

当js发出一个ajax请求之后,请求其实是发送到了服务器,浏览器会对请求进行校验。

解决方案

CORS

CORS(Cross-Origin Resource Sharing)是最正统的跨域解决方案。

CORS的基本理念:

  • 只要服务器明确表示允许,则校验通过。
  • 服务器明确表示拒绝或没有表示,则表示不通过。
请求分类

CORS 将请求分为两类:简单请求预检请求

简单请求: 只要全部满足下面条件,就是简单请求

  • 请求方法是 GET,POST,HEAD之一。
  • 头部字段满足CORS安全规范(详见W3C):浏览器默认自带的头部字段都是满足安全规范的,只要开发者不改动和新增头部,就不会打破次规则。
  • 如果有 Content-Type,必须是下列值中的一个。
    • text/plain
    • mutltipart/form-data
    • application/x-wwww-form-urlenccoded

预检请求: 只要不是简单请求,就全部是预检请求

简单请求的校验规则

会将请求发送出去,然后在头部带上一个Origin:当前页面源的字段,让服务器去判定是否可以,服务器会在响应头里面带上一个 Access-Control-Allow-Origin:源字段。或者直接将值写为*。

预检请求的校验规则
  1. 发送预检请求

不会发送真实的请求,先发送一个预检请求,如下图:

image.png

服务器自行去判断是否响应请求,如下图:

image.png

  1. 发送真实请求

当预检请求通过以后,浏览器会发送一个跟普通请求一样的真实请求。

细节1:默认情况下,跨域请求都不会携带cookie,这样一来如果需要去做一些权限的话就会出问题。

不过可以根据配置:服务器需要带一个响应头去允许携带凭证,如果带了cookie,服务器 Access-control Allow Origin就不能设置为 * image.png

细节2:关于跨域获取响应头

image.png

JSONP

image.png 只能发送get请求。

容易产生安全隐患:

恶意攻击者可能利用callback=恶意函数的方式实现xss攻击

代理

image-20230115133326930

// proxy
app.get('/hero', async (req, res) => {
  const axios = require('axios');
  const resp = await axios.get('https://pvp.qq.com/web201605/js/herolist.json');
  // 使用CORS解决对代理服务器的跨域
  res.header('access-control-allow-origin', '*');
  res.send(resp.data);
});