0


跨域及解决方案

文章目录

一、什么是跨域

1. 同源策略

  • 跨域是指一个源下的文档或脚本想要去请求另一个源下的资源。
  • 非同源请求,也就是协议、端口、主机其中一项不相同的时候。
  • 比如:<link><script><img>等Dom标签,还有在样式中嵌入的文件外链,以及JS发起的ajax请求等都存在跨域。

2. 目的

  • 主要是用来防止 CSRF 攻击的。简单点说,CSRF 攻击是利用用户的登录态发起恶意请求

3. 哪些不会被跨域限制?

  • 页面中的链接,重定向以及表单提交是不会受到同源策略限制的。
  • 我们还发现凡是拥有”src”这个属性的标签都拥有跨域的能力,比如<\script>、<\img>、<\iframe>

三、4 种跨域情况

当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域

  1. 不同域名属于跨域,如:www.a.comwww.b.com,另外www.a.comwww.a.com.cn也属于不同域名。
  2. 主域名和子域名(二级域名、三级域名等)跨域,如:www.a.com 和 bbs.a.com 跨域。
  3. 不同协议属于跨域,如:http://www.a.comhttps://www.a.com。
  4. Ip和域名属于跨域,如:123.23.23.12 和 www.a.com。

四、访问限制

除了跨域请求之外,还有以下限制

储存

  • 当前域下的 js 脚本不能够访问其他域下的 cookie、localStorage 和 indexDB。浏览器中存储用户数据时,会标记数据的来源(origin),当JS脚本访问本地数据时,会检查它的orign是否一致,不一致就拒绝访问。

操作DOM

  • 当前域下的 js 脚本不能够操作访问操作其他域下的 DOM。

五、跨域解决方案

1. JSONP

(1)简介

JSONP全称叫

JSON with Padding

,将数据填充进回调函数,是一个非官方的协议

(2)原理

简单来说,就是**利用

<script>

标签没有跨域限制**。

客户端

(请求地址、参数(包含回调函数名)、全局函数(接收数据))

  • 全局定义一个函数A,用于处理响应数据。(script)
  • script标签的src属性中,设置请求地址参数,将函数A的函数名作为参数callback的值进行传递。

服务端

  • 收到请求后,返回一个函数A的调用,将响应数据传入函数A中。

结果

客户端接收到响应就相当于:

  • 页面中定义函数A,对传入的参数进行处理。
  • 用来发送请求是script相当于:调用函数A,将响应数据作为函数的参数。

注意:请求中callback这个键名需要和后端约定好。

**(3)代码演示 **

客户端

<script>var script = document.createElement('script');
    script.type ='text/javascript';// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src ='http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);// 回调执行函数functionhandleCallback(res){alert(JSON.stringify(res));}</script>

服务端返回内容

handleCallback({"success":true,"user":"admin"})

(4)特点

  • 具有局限性, 仅支持get方法
  • 不安全,可能会遭受XSS攻击

2. CORS

(1)简介

  • CORS是一个W3C标准,全称是跨域资源共享,它允许浏览器发出跨域请求。
  • 它需要浏览器和后端同时支持。目前所有浏览器都支持CORS 通信(IE浏览器不低于IE10),实现 CORS 通信的关键是后端
  • 简单来说,如果遇到跨域请求,浏览器能够发出请求,但是需要服务端支持,如果服务端不支持,返回的内容就会被浏览器拦截。

(2)实现

  • 服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。

(3)简单请求

请求过程

  • 对于简单请求,浏览器会直接发出CORS请求,它会在请求的头信息中增加一个Origin字段,该字段用来说明本次请求来自哪个源(协议+端口+域名).
  • 服务器会根据这个值来决定是否同意这次请求。如果在允许范围内,响应信息中额外携带 Access-Control-Allow-Origin字段,如果不再允许范围内,就没有这个头部信息。浏览器根据这个头部来判断是否要展示数据。如果没有这个响应头部信息,数据就会被拦截。

使用以下请求方法属于简单请求

  • GET
  • HEAD
  • POST

满足简单请求条件的还有很多情况,这里不一一列举。

(4)复杂请求

  • 非简单请求是对服务器有特殊要求的请求,比如请求方法为DELETE或者PUT等。
  • 非简单请求的CORS请求会在正式通信之前进行一次HTTP查询请求,称为预检请求
  • 在这个预检请求,是浏览器自动发出,询问服务器当前所在的网页是否在服务器允许访问的范围内,以及可以使用哪些HTTP请求方式和头信息字段,只有得到肯定的回复,才会进行正式的HTTP请求。(否则就会报错)
  • 预检请求使用的请求方法是OPTIONS,表示这个请求是来询问的。他的头信息中的关键字段是Origin,表示请求来自哪个源。除此之外,头信息中还包括请求方法和会额外发送的头信息。(两个字段:- Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。- Access-Control-Request-Headers: 该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。)
  • 服务器在收到浏览器的预检请求之后,会根据请求头部(源、请求方式等)进行判断,只有服务端返回允许请求的响应,浏览器才会发送正式的请求,否则报错。

(5)减少OPTIONS请求

  • OPTIONS请求次数过多就会损耗页面加载的性能,降低用户体验度。可以缓存预检结果。
  • 通过响应头来设置预检请求结果的缓存时间
  • 要减少OPTIONS请求次数,可以后端在请求的返回头部添加:Access-Control-Max-Age:number。它表示预检请求的返回结果可以被缓存多久,单位是秒。
  • 该字段只对完全一样的URL的缓存设置生效,所以设置了缓存时间,在这个时间范围内,再次发送请求就不需要进行预检请求了。

(6)Cookie

  • 默认情况下在CORS请求是不带 cookie 的。
  • 需要在服务端和客户端都进行设置同意。
  • 在客户端,是在代码中设置 XMLHttpRequest 的 withCrendetails 属性
  • 服务端进行相应的设置就可以发送cookie了。

(7)优缺点

优点

  1. 支持所有http请求
  2. 安全性比JSONP高
  3. 配置简单

缺点

  1. 不兼容老版本浏览器(IE浏览器不低于IE10)
  2. 需要服务端支持

(8)浏览器拦截

跨域请求发出:同CORS请求(有简单请求和复杂请求)

浏览器对跨域拦截:

  1. 如果响应头中没有允许跨域访问的配置,则不加载,并报出响应异常
  2. 如果响应头中有允许跨域访问的设置,则正常加载数据。

3. Proxy

  • 代理(Proxy)也称网络代理,是一种特殊的网络服务,允许一个(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。
  • 同源策略是浏览器的限制,服务端没有这个限制,也就是说从一个服务端向另一个服务端发起请求并无跨域。
  • 一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击。

方案一

  • 如果是通过vue-cli脚手架工具搭建项目,我们可以通过webpack为我们起一个本地服务器作为请求的代理对象
  • 通过该服务器转发请求至目标服务器,得到结果再转发给前端,但是最终发布上线时如果web应用和接口服务器不在一起仍会跨域在vue.config.js文件,新增以下代码amodule.exports ={devServer:{host:'127.0.0.1',port:8084,open:true,// vue项目启动时自动打开浏览器proxy:{'/api':{// '/api'是代理标识,用于告诉node,url前面是/api的就是使用代理的target:"http://xxx.xxx.xx.xx:8080",//目标地址,一般是指后台服务器地址changeOrigin:true,//是否跨域pathRewrite:{// pathRewrite 的作用是把实际Request Url中的'/api'用""代替'^/api':""}}}}}通过axios发送请求中,配置请求的根路径axios.defaults.baseURL = '/api'

方案二

  • 通过node服务端实现代理请求转发,以express框架为例var express = require('express');const proxy = require('http-proxy-middleware')const app = express()app.use(express.static(__dirname + '/'))app.use('/api', proxy({ target: 'http://localhost:4000', changeOrigin: false }));module.exports = app

方案三

  • 通过配置nginx实现代理server { listen 80; # server_name www.josephxia.com; location / { root /var/www/html; index index.html index.htm; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:3000; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }}

4. 总结

  1. CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案JSONP只支持GET请求
  2. JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
  3. 不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制。
  4. 日常工作中,用得比较多的跨域方案是CORSNginx反向代理
标签: 安全

本文转载自: https://blog.csdn.net/weixin_51670675/article/details/127379883
版权归原作者 Palate 所有, 如有侵权,请联系我们删除。

“跨域及解决方案”的评论:

还没有评论