IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 前端网络基础 - 跨域xhr/fetch -> 正文阅读

[网络协议]前端网络基础 - 跨域xhr/fetch

目录

浏览器的同源策略

如何定义同源

什么是跨域

JSONP跨域

script标签的特点

JSONP实现原理

JSONP的缺点

JSONP的安全问题防护策略

CORS响应头跨域

Access-Control-Allow-Origin

跨域请求的分类

简单跨域请求

非简单跨域请求

对比JSONP跨域

代理服务器跨域


浏览器的同源策略

同源策略是浏览器特有的一种安全机制,它主要用于限制不同的源之间的数据交互。

举个例子

http://192.168.3.154:5500/index.html 想去访问 http://192.168.3.9:80/user,会被浏览器限制。

当?http://192.168.3.154:5500/index.html 去访问?http://192.168.3.9:80/user 时

可以发现,浏览器端报错CORS error,即Cross-origin resource sharing 跨源资源共享发生错误,错误原因就是浏览器同源策略限制了本次不同源间数据的交互。

那么浏览器具体是如何限制的呢?

通过服务器端的日志

收到请求了http://192.168.3.154:5500
服务器响应已经发出

我们可得:

浏览器没有限制非同源请求的发送,浏览器也没有限制服务器的响应动作,浏览器只是限制了网页接收非同源的响应。

即:服务器的响应被浏览器收到了,但是浏览器没有将非同源响应交给发起的网页。

如何定义同源

同源:即 protocol(协议)、host(主机)、port(端口)相同

我们通过下面的例子来深入理解下同源

浏览器网页 http://192.168.3.9/index.html 请求以下源时,是否会发生CORS error,即判断二者是否同源?

https://192.168.3.9/user不同源,协议不同
http://192.168.0.1/user不同源,主机不同
http://192.168.3.9:8080/user不同源,端口不同,http协议默认端口80,可以省略不屑

另外,我们还需要注意 IP地址和其对应域名之间是否算同源?

我们设置 IP地址 192.168.3.9?的域名为?www.qfc.com

这里我将本地主机的DNS解析文件hosts中配置增加一行如上,则可以保证www.qfc.com会被解析为192.168.3.9

然后修改服务器代码,让服务器既可以提供前台页面index.html,也可以提供服务器业务处理接口app.js,保证index.html和app.js中接口同源

如下app.js中,提供了index.html访问路由,以及/user接口访问路由?

index.html中fetch请求http://www.qfc.com/user接口

?但是浏览器访问的http://192.168.3.9/index.html

可以发现,即使http://www.qfc.com/user请求的主机是自身IP对应的域名,也会被视为不同源。

什么是跨域

跨域其实就是同源的反义词,跨域可以理解为非同源。

随着前后端分离的发展,前端独立部署,访问非同源的后端服务器,已经是一种普遍现象。

但是由于浏览器同源策略的影响,跨域请求被限制了,所以我们需要一种可以规避同源策略,实现跨域请求的解决方案。

JSONP跨域

script标签的特点

在HTML中,有一些标签也可以发起HTTP请求,比如script标签,link标签,img标签,form标签,且被允许跨域。

  • link,img标签都是单纯的引入资源文件
  • form标签用于收集用户输入并发送,但是发送成功会跳转到新网页,并将服务器响应作为新网页的内容
  • script标签可以引入外部js文件,并执行引入的js文件的代码

其中,script标签由于其可以执行引入的js文件的代码,再加上其跨域特性,让script标签可以用来做一些超出其设计初衷的事。

script标签会发起HTTP GET去请求服务器上的js文件,所以script标签可以用于实现HTTP GET跨域请求。

如下例子,我们使用script引入了非同源的某cdn服务器上的axios.min.js,然后使用axios发起xhr请求同源接口

?可以发现,虽然axios.min.js是非同源服务器上的,但是script标签也可以跨域引入。

JSONP实现原理

那么如何使用script标签实现普适的跨域请求呢?

啥叫普适的跨域请求,举个例子,我们可以利用script标签请求上例中http://192.168.3.9/user接口,并获得接口响应。

这个过程,有两个点,一是发送HTTP GET请求http://192.168.3.9/user,这点不难,直接将http://192.168.3.9/user作为script标签src值即可

还有一点,如何获取http://192.168.3.9/user返回值?

我们知道常规的http://192.168.3.9/user接口返回的就是一个文本内容,这个文本内容可能是html字符串,也可能是json字符串,或者其他,但是script标签期望引入的文件内容是js代码,这样就可以执行了。

所以,我们可以将实际文本内容的HTTP响应,封装进js函数入参中,这样script标签引入后,就会自动执行js函数,这样我们就可以收到入参了。

如下示例

http://127.0.0.1:5500/index.html 通过script标签HTTP GET请求 http://192.168.3.9/user,得到响应文本 'fn("get user success")',script标签会将 'fn("get user success")'作为js代码执行,然后调用fn函数,而我们又在http://127.0.0.1:5500/index.html提前准备了一个fn函数,所以"get user success"会被作为入参传递到fn函数中。

这样就完成了依靠script标签进行跨域普适请求。

但是以上代码有一处不足,就是前端和后端需要约定好函数的名字,比如fn,而fn其实并不是业务需要的,所以没必要进行前后端约定。

我们知道HTTP GET请求可以在URL中携带参数,所以我们只要将函数名字作为URL查询参数传递到后端,后端就无需关心函数名了。

?以上基于script标签实现的跨域纯属于钻漏洞,是一种无奈之举,这种跨域方案被命名为JSONP。

JSONP的缺点

JSONP的缺点也很明显,只能实现HTTP GET请求的跨域,对于其他请求方式无能为力,因为script标签只能发起HTTP GET请求。

另外JSONP要求前后端协作,前端和后端代码开发起来都很别扭,不符合规范的代码要求。

同时由于JSONP实现了跨域,所以很容易被恶意网站利用,因为任何网站都可以通过script标签引入可以跨域的目的源接口,有很大的安全问题,除非后端对请求源做限制。

JSONP的安全问题防护策略

这里演示下使用请求头中的Referer信息来做校验,即服务器端根据请求头中的Referer来判断请求源,并限制可以跨域的Referer源,如下trusted_domain是可信源,如果不在可信源的Referer则响应401,无权操作

?

下面在http://127.0.0.1:5500/index.html?通过script标签 请求 http://192.168.3.9/user,结果得到响应401

而在http://192.168.3.154:5500/index.html就可以正常访问http://192.168.3.9/user

以上就是服务器端通过请求头中Referer信息判断请求源的协议,主机,端口,来进行限制访问。

但是HTTP请求头中的Referer信息是可以被篡改的(比如使用burpsuite),所以基于Referer来判断是不可信的。

其实对于服务器来说,来自前端的请求信息都不可信,无论是origin请求头,还是referer请求头,它们都可能被篡改,所以我们不应该让服务器来做非同源校验。而真正适合非同源校验的还得是浏览器,因为第一手请求是浏览器发出去的,buripsuite这些拦截工具都是吃的浏览器的剩饭。所以对于浏览器来说,请求头中referer,origin都是可信的。

CORS响应头跨域

前面分析了,JSONP跨域并不安全,即使在服务器侧做了请求源限制,意义也不大,因为服务器目前只能靠请求头中的referer或origin来判断请求源,但是请求头中的referer或origin很容易被篡改。

浏览器就是请求的制造者,浏览器可以拿到第一手的请求源信息,且不存在被篡改的风险,所以跨域请求的源限定适合交给浏览器来做,而服务器只需要告诉浏览器允许哪些源的跨域请求即可。

Access-Control-Allow-Origin

所以,为了实现安全的跨域资源共享,浏览器和服务器之间约定,当服务器接口需要支持跨域请求时,服务器可以在接口的HTTP响应头中包含Access-Control-Allow-Origin字段,该字段的值就是允许跨域请求的源。

浏览器会根据HTTP响应头中的Access-Control-Allow-Origin获取到允许发起跨域请求的源,并对比实际发起请求的源,若相同则浏览器会将响应正常返回给发起者,若不同,则报错CORS error。

Access-Control-Allow-Origin请求头的值有两种情况

Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: <origin>

当值为*时,表示允许所有源进行跨域请求。当值为特定源时,表示只允许该源进行跨域请求。

但是CORS跨域是有要求的,并不是说非同源服务器接口响应头添加了Access-Control-Allow-Origin就可以了。

跨域请求的分类

浏览器将请求分为了两类, 简单请求 和 非简单请求。

简单请求需要满足如下条件:

  • 请求方式只能是 get、post、head之一
  • 请求头只能包含如下 accept、accept-lanuage、content-lanuage、content-type
  • content-type值只能是 application/x-www-form-urlencoded、multIpart/form-data、text/plain 之一

不满足以上条件的请求就是非简单请求。

所以跨域请求也被分为了两类,简单跨域请求 和 非简单跨域请求。

简单跨域请求

浏览器遇到简单跨域请求时,会直接发送,并且会在请求头中添加一个Origin字段,该字段用于告知服务器当前请求来自于哪个站点,Origin值包含了发起请求的源的协议、主机、端口。

服务器可以根据请求中的Origin头过滤掉一些不可信源的请求,以减轻服务器的资源消耗。而对于可信源的请求,则走正常的服务器业务流程,并在响应头中添加Access-Control-Allow-Origin:可信源,用于告知浏览器该源可以进行跨域请求。

?

非简单跨域请求

浏览器在遇到非简单请求时(如PUT,DELETE请求,或者content-type:application/json的请求),不会直接发送,而是会先发送一个预检请求。

所谓预检请求preflight,即在发送正式请求之前,先发送一次HTTP OPTIONS请求到服务器,用于预先检测服务器是否支持即将发送的正式请求。

?

预检请求会在请求头中加入

  • Origin:请求源的协议、主机、端口
  • Access-Control-Request-Method:当前请求方法
  • Access-Control-Request-Header:简单头部以外的请求头

服务器可以根据以上请求头做相应过滤,以减轻服务器压力。对于符合要求的请求源,请求方法,请求头,服务器需要响应如下头部,预检请求会将如下信息告知浏览器允许该跨域请求的得到响应。

  • Access-Control-Allow-Origin:可信源
  • Access-Control-Allow-Methods:可用请求方法
  • Access-Control-Allow-Headers:可用请求头

?

如下示例,服务器没有做过滤,直接设置了Access-Control-Allow-相关的响应头,浏览器收到预检请求的响应后,知道了可用的请求方法有GET,PUT,可用的请求头有test1,test2

所以下面请求源,请求方法,请求头都符合要求,所以浏览器将响应正常返回了?

?


如果使用了不可用的请求方法,如DELETE,则报错CORS error

如果使用了不可用的头,如test3,则报错CORS error

?

所以即使服务器设置了Access-Control-Allow-Origin,且请求源符合就是其设置的可信源,也不能保证成功的CORS,对于非简单请求而言,还要服务器设置Access-Control-Allow-Headers和Access-Control-Allow-Methods。

对比JSONP跨域

CORS响应头跨域更加安全,且支持所有HTTP METHOD,另外只需要服务器在响应中增加几个头字段即可,前端不需要任何改动。

代理服务器跨域

?我们需要搞清楚 同源策略 是浏览器内置的安全策略,所有从浏览器发出的请求都要符合同源策略,如果需要通过浏览器发送跨域请求,则需要借助JSONP,CORS等跨域技术,而JSONP,CORS实际上也是基于浏览器的,它们并不是绕过浏览器同源策略,而是走浏览器同源策略开的后门。

那么有没有办法绕过浏览器的同源策略呢?

有,那就是不通过浏览器发出跨域请求。

那么如何实现呢?大致流程如下:

网页? →? 同源服务器? →? 非同源服务器

即由网页同源的代理服务器作为中间件,来转发网页的请求到非同源服务器,这样就绕过了浏览器发送跨域请求。

此时,我们需要注意的是,如果目的服务器自己做了请求源过滤,则我们需要做一些欺骗收到,即设置虚假的referer或origin头来迷惑目的服务器

下面我准备两台服务器:

1、目的服务器

目的服务器没有设置CORS头,也没有做JSONP接口

2、代理服务器?

代理服务器负责提供前台网页(这里使用了express.static静态资源托管负责提供前台网页),并且负责转发请求到目的服务器

我们知道如果直接在http://127.0.0.1/index.html中请求 http://192.168.3.9/user 会报错CORS error,但是现在?http://127.0.0.1/index.html中请求的是同源的代理服务器接口 http://127.0.0.1/user,所以不会报错CORS error。

而代理服务器收到http://127.0.0.1/user 请求后,会立即转发给http://192.168.3.9/user,由于该跨域请求是通过服务器发送的,而不是浏览器,所以不受浏览器同源策略影响。

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:59:55  更:2022-02-28 16:02:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年10日历 -2024/10/5 13:24:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码