您当前的位置:首页 > 新闻 > 科技

聊聊浏览器同源策略与跨域方案详解

时间:2020-07-19 09:42:32  来源:  作者:

开发出高性能的 Web 应用固然重要,但安全问题也不容小觑。本文我们继续以 HTTP 为线索,展开来讲一讲浏览器安全相关的同源策略。

浏览器的同源策略(Same Origin Policy)

源(Origin)是由 URL 中协议、主机名(域名 domain)以及端口共同组成的部分。在下面的网址中,源由协议 https、主机名 kaiwu.lagou.com 和默认端口 443 共同组成。

URL 中的源

如果两个 URL 的源相同,我们就称之为同源。下面的 3 个 URL 和示例 URL 都是不同的源。

http://kaiwu.lagou.com/course/courseInfo.htm?courseId=180#/content:协议不同。

https://kaiwu.lagou.com:80/course/courseInfo.htm?courseId=180#/content:端口不同。

https://lagou.com/course/courseInfo.htm?courseId=180#/content:主机名不同。

而下面 2 个网址和示例 URL 都是同源。

https://kaiwu.lagou.com/course/courseInfo.htm?courseId=288#/sale:请求参数不同。

https://kaiwu.lagou.com:URL 路径不同。

当一个源访问另一个源的资源时就会产生跨源。同源策略就是用来限制其中一些跨源访问的,包括访问 iframe 中的页面、其他页面的 cookie 访问以及发送 AJAX 请求。最常见的跨源场景是域名不同,即常说的“跨域”。本课时也按照约定俗成的说法,用“跨域”来指代“跨源”。

同源策略在保障安全的同时也带来了不少问题,比如 iframe 中的子页面与父页面无法通信,浏览器与其他服务端无法交互数据。所以我们需要一些跨域方案来解决这些问题。

请求跨域解决方案

对于浏览器请求跨域,常用的有下面 4 种方法。

跨域资源共享

跨域资源共享(CORS,Cross-Origin Resource Sharing)是浏览器为 AJAX 请求设置的一种跨域机制,让其可以在服务端允许的情况下进行跨域访问。主要通过 HTTP 响应头来告诉浏览器服务端是否允许当前域的脚本进行跨域访问。

跨域资源共享将 AJAX 请求分成了两类:简单请求和非简单请求。其中简单请求符合下面 2 个特征。

请求方法为 GET、POST、HEAD。

请求头只能使用下面的字段:Accept(浏览器能够接受的响应内容类型)、Accept-Language(浏览器能够接受的自然语言列表)、Content-Type (请求对应的类型,只限于 text/plain、multipart/form-data、Application/x-www-form-urlencoded)、Content-Language(浏览器希望采用的自然语言)、Save-Data(浏览器是否希望减少数据传输量)。

任意一条要求不符合的即为非简单请求。

对于简单请求,处理流程如下:

浏览器发出简单请求的时候,会在请求头部增加一个 Origin 字段,对应的值为当前请求的源信息;

当服务端收到请求后,会根据请求头字段 Origin 做出判断后返回相应的内容。

浏览器收到响应报文后会根据响应头部字段 Access-Control-Allow-Origin 进行判断,这个字段值为服务端允许跨域请求的源,其中通配符“*”表示允许所有跨域请求。如果头部信息没有包含 Access-Control-Allow-Origin 字段或者响应的头部字段 Access-Control-Allow-Origin 不允许当前源的请求,则会抛出错误。

当处理非简单的请求时,浏览器会先发出一个预检请求(Preflight)。这个预检请求为 OPTIONS 方法,并且添加了 1 个请求头部字段 Access-Control-Request-Method,值为跨域请求所使用的请求方法。

下图是一个预检请求的请求报文和响应报文。因为添加了不属于上述简单请求的头部字段,所以浏览器在请求头部添加了 Access-Control-Request-Headers 字段,值为跨域请求添加的请求头部字段 authorization。

聊聊浏览器同源策略与跨域方案详解

预检请求头部信息

在服务端收到预检请求后,除了在响应头部添加 Access-Control-Allow-Origin 字段之外,至少还会添加 Access-Control-Allow-Methods 字段来告诉浏览器服务端允许的请求方法,并返回 204 状态码。

在上面的例子中,服务端还根据浏览器的 Access-Control-Request-Headers 字段回应了一个 Access-Control-Allow-Headers 字段,来告诉浏览器服务端允许的请求头部字段。

浏览器得到预检请求响应的头部字段之后,会判断当前请求服务端是否在服务端许可范围之内,如果在则继续发送跨域请求,反之则直接报错。

JSONP

JSONP(JSON with Padding)的大概意思就是用 JSON 数据来填充,怎么填充呢?结合它的实现方式可以知道,就是把 JSON 数填充到一个回调函数中。这种比较 hack 的方式,依赖的是 script 标签跨域引用 js 文件不会受到浏览器同源策略的限制。

下面以一个具体例子来讲解它的具体实现方式。

假设我们要在 http://ww.a.com 中向 http://www.b.com 请求数据。

1.全局声明一个用来处理返回值的函数 fn,该函数参数为请求的返回结果。

function fn(result) {
  console.log(result)
}

2.将函数名与其他参数一并写入 URL 中。

var url = 'http://www.b.com?callback=fn¶ms=...';

3.创建一个 script 标签,把 URL 赋值给 script 的 src。

var script = document.createElement('script');
script.setAttribute("type","text/JAVAscript");
script.src = url;
document.body.appendChild(script);

4.当服务器接收到请求后,解析 URL 参数并进行对应的逻辑处理,得到结果后将其写成回调函数的形式并返回给浏览器。

fn({
  list: [],
  ...
})

5.在浏览器收到请求返回的 js 脚本之后会立即执行文件内容,即在控制台打印传入的数据内容。

JSONP 虽然实现了跨域请求,但也存在 3 个问题:

  • 只能发送 GET 请求,限制了参数大小和类型;
  • 请求过程无法终止,导致弱网络下处理超时请求比较麻烦;
  • 无法捕获服务端返回的异常信息。

Websocket

Websocket 是 html5 规范提出的一个应用层的全双工协议,适用于浏览器与服务器进行实时通信场景。

什么叫全双工呢?

这是通信传输的一个术语,这里的“工”指的是通信方向,“双工”是指从客户端到服务端,以及从服务端到客户端两个方向都可以通信,“全”指的是通信双方可以同时向对方发送数据。与之相对应的还有半双工和单工,半双工指的是双方可以互相向对方发送数据,但双方不能同时发送,单工则指的是数据只能从一方发送到另一方。

下面是一段简单的示例代码。在 a 网站直接创建一个 WebSocket 连接,连接到 b 网站即可,然后调用 WebScoket 实例 ws 的 send() 函数向服务端发送消息,监听实例 ws 的 onmessage 事件得到响应内容。

var ws = new WebSocket("ws://b.com");
ws.onopen = function(){
  // ws.send(...);
}
ws.onmessage = function(e){
  // console.log(e.data);
}

代理转发

跨域是为了突破浏览器的同源策略限制,既然同源策略只存在于浏览器,那可以换个思路,在服务端进行跨域,比如设置代理转发。这种在服务端设置的代理称为“反向代理”,对于用户而言是无感知的。

另一种在客户端使用的代理称为“正向代理”,主要用来代理客户端发送请求,用户使用时必须配置代理服务器的网址,比如常用的 VPN 工具就属于正向代理。

代理转发实现起来非常简单,在当前被访问的服务器配置一个请求转发规则就行了。

下面的代码是 webpack-dev-server 配置代理的示例代码。当浏览器发起前缀为 /api 的请求时都会被转发到 http://localhost:3000 这个网址,然后将响应结果返回给浏览器。对于浏览器而言还是请求当前网站,但实际上已经被服务端转发。

// webpack.config.js
module.exports = {
  //...
  devServer: {
    proxy: {
      '/api': 'http://localhost:3000'
    }
  }
};

Nginx 服务器上配置同样的转发规则也非常简单,下面是示例配置。

location /api {
    proxy_pass   http://localhost:3000;
}

通过 location 指令匹配路径,然后通过 proxy_pass 指令指向代理地址即可。

页面跨域解决方案

除了浏览器请求跨域之外,页面之间也会有跨域需求,例如使用 iframe 时父子页面之间进行通信

postMessage

HTML5 推出了一个新的函数 postMessage() 用来实现父子页面之间通信,而且不论这两个页面是否同源。

举例来说,如果父页面 https://lagou.com 要向子页面 https://kaiwu.lagou.com 发消息,可以通过下面的代码实现。

// https://lagou.com
var child = window.open('https://kaiwu.lagou.com');
child.postMessage('hi', 'https://kaiwu.lagou.com');

上面的代码通过 window.open() 函数打开了子页面,然后调用 child.postMessage() 函数发送了字符串数据“hi”给子页面。

在子页面中,只需要监听“message”事件即可得到父页面的数据。代码如下:

// https://kaiwu.lagou.com
window.addEventListener('message', function(e) {
  console.log(e.data);
},false);

同样的,父页面也可以监听“message”事件来接收子页面发送的数据。子页面发送数据时则要通过 window.opener 对象来调用 postMessage() 函数。

// https://kaiwu.lagou.com
window.opener.postMessage('hello', 'https://lagou.com');

改域

对于主域名相同,子域名不同的情况,可以通过修改 document.domain 的值来进行跨域。如果将其设置为其当前域的父域,则这个较短的父域将用于后续源检查。

比如,有一个页面,它的地址是 https://www.lagou.com/parent.html,在这个页面里面有一个 iframe,其 src 是 http://kaiwu.lagou.com/child.html。

这时只要把 http://www.lagou.com/parent.html 和 http://kaiwu.lagou.com/child.html 这两个页面的 document.domain 都设成相同的域名,那么父子页面之间就可以进行跨域通信了,同时还可以共享 cookie。

但要注意的是,只能把 document.domain 设置成更高级的父域才有效果,例如在 http://kaiwu.lagou.com/child.html 中可以将 document.domain 设置成 kaiwu.lagou.com。

总结

本文介绍了浏览器的同源策略,并分别从请求跨域与页面跨域两个方向介绍了几种常用的跨域方案。

对于请求跨域,包括跨域资源共享、JSONP、Websocket、代理转发 4 种方式推荐优先使用代理转发和跨域资源共享。对于页面跨域,包括 postMessage 和改域 2 种方式,使用频率没有请求跨域那么高,记住 2 种方式实现原理就好。

最后留一道思考题:说一说你还知道浏览器的哪些安全策略?



Tags:浏览器   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
一. 配置yum源在目录 /etc/yum.repos.d/ 下新建文件 google-chrome.repovim /etc/yum.repos.d/google-chrome.repo按i进入编辑模式写入如下内容:[google-chrome]name=googl...【详细内容】
2021-12-23  Tags: 浏览器  点击:(7)  评论:(0)  加入收藏
Safari是苹果在iPhone和iPad上的默认网络浏览器。虽然我们天天都在使用,但是,你是否深入研究了Safari的所有功能和设置?"无痕浏览"、"阅读器"视图和下载文件等标准选项只是其...【详细内容】
2021-12-16  Tags: 浏览器  点击:(21)  评论:(0)  加入收藏
大家好,我是Stark-C。油猴简介【油猴】一款免费的浏览器扩展和最为流行的用户脚本管理器,它是一个附加组件(扩展程序),让用户安装一些脚本使大部分HTML为主的网页改变得更方便易...【详细内容】
2021-12-13  Tags: 浏览器  点击:(46)  评论:(0)  加入收藏
年末,又到了各大厂商盘点年度最佳的时候了。不过让世超感到意外的是 Google 竟然给自己 Chrome 的插件,做了一个 2021 年精选集锦,挑选出了 13 款今年最热门的 Chrome 插件。...【详细内容】
2021-12-13  Tags: 浏览器  点击:(19)  评论:(0)  加入收藏
当我们浏览知乎、Youtube、贴吧、CSDN等等,总会遇到服务商一些广告;复制文章的时候,剪切板总是自带一些版权信息;还有一些网页配色很亮,眼睛看着很不舒服。反正就是各种不爽。给...【详细内容】
2021-12-08  Tags: 浏览器  点击:(27)  评论:(0)  加入收藏
谷歌访问助手插件是专门针对chrome谷歌浏览器而开发的一款访问插件,可以为谷歌搜索,谷歌chrome商店,gmail邮箱提供加速服务,解决打不开的问题。这款插件可以帮助我们在使用谷歌...【详细内容】
2021-12-03  Tags: 浏览器  点击:(13)  评论:(0)  加入收藏
微软似乎正努力增强 Edge 浏览器和网页端 Office 之间的整合联动。Reddit 社区用户 u/Leopeva64-2指出,Edge Canary 的最新版本在标签的右键菜单中有一个新选项。如果你在窗...【详细内容】
2021-11-11  Tags: 浏览器  点击:(35)  评论:(0)  加入收藏
IOS15推送后,Safari也支持扩展了,这里给大家推荐几款Safari扩展软件,希望对你手机使用有所帮助。 扩展功能 IOS15可以通过设置——Safari浏览器——更多扩...【详细内容】
2021-11-08  Tags: 浏览器  点击:(135)  评论:(0)  加入收藏
一、判断是否IE浏览器(支持判断IE11与edge)function IEVersion() {var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串var isIE = userAgent.indexOf("comp...【详细内容】
2021-11-02  Tags: 浏览器  点击:(40)  评论:(0)  加入收藏
作为当今最差的浏览器,虽说IE即将推出历史的舞台,但是因为项目需要还是需要支持。那么必须判断是否是IE,如果是IE,需要做些特殊处理。document.documentMode 是IE特有的属性,可以...【详细内容】
2021-10-25  Tags: 浏览器  点击:(36)  评论:(0)  加入收藏
▌简易百科推荐
非法购买公民信息、开发人脸认证规避技术……今年年初,广东省公安厅网安部门侦破全国首例破解“青少年防沉迷系统”的新型网络犯罪案件,抓获犯罪嫌疑人13名,查处非...【详细内容】
2021-12-28    人民日报客户端  Tags:数据安全步   点击:(5)  评论:(0)  加入收藏
就在今天,腾讯方面宣布将在2022年1月31日下架企业QQ和营销QQ,其实这一消息的降临并不让笔者意外,因为早在今年的10月28日20点之后,企业QQ和营销QQ就被停止了续费服务。相信很多...【详细内容】
2021-12-27  科技探险家    Tags:企业QQ   点击:(20)  评论:(0)  加入收藏
日前,上海交通大学发布《全球电竞之都评价报告》,对全球15个致力于发展电竞之都的城市进行评价,上海作为中国城市电竞发展的排头兵,其拥有众多优质电竞企业及完整产业集群,因此排...【详细内容】
2021-12-27  经济日报    Tags:电竞   点击:(3)  评论:(0)  加入收藏
为优化网络氛围环境,微博又开始整顿用户信息了。本月月初,微博官方发布公告,要求昵称中带有如“二货”“SB”“瘪三”“娘炮”等明显低俗或侮辱性词汇的用户尽快修改,否则将面临...【详细内容】
2021-12-24  运了个营    Tags:微博   点击:(10)  评论:(0)  加入收藏
昨日谷歌宣布,自2022年12月19日开始停止对OnHub的软件支持,OnHub路由器仍将提供Wi-Fi信号,但用户无法用谷歌Home应用程序管理它。无法更新Wi-Fi网络设置、添加额外的Wifi设备或...【详细内容】
2021-12-22  雷峰网    Tags:Google OnHub   点击:(5)  评论:(0)  加入收藏
IT之家 12 月 20 日消息,百度网盘青春版 iOS 客户端今日晚间率先开启内测,安卓客户端将在稍后内测。使用苹果 iPhone 的IT之家小伙伴可以点此下载内测版,需要先下载 TestFlight...【详细内容】
2021-12-21  IT之家    Tags:百度网盘   点击:(10)  评论:(0)  加入收藏
对于拼车单,是接还是不接,不少网约车司机表示很矛盾。接吧,钱少事多,常常跑了个寂寞,不接吧,车多客少,挑三拣四没饭吃。 在平台大力推广拼车单之下,不少司机迫于生活压力,最终还是打...【详细内容】
2021-12-17  网约车情报分享    Tags:滴滴   点击:(9)  评论:(0)  加入收藏
蓝鲸TMT频道12月16日讯,据饿了么官方微信公众号,近日,在圆桌会上,蓝骑士与平台交流了配送安全问题。饿了么表示,线上将技术手段融入安全防护;线下将持续进行安全培训,并试点智能头...【详细内容】
2021-12-17    金融界  Tags:饿了么   点击:(24)  评论:(0)  加入收藏
开源最前线(ID:OpenSourceTop) 猿妹编译项目地址: https://github.com/restic/restic全球知名代码托管平台 GitHub 今天就重磅发布了今年的年度报告——《2021 年度 O...【详细内容】
2021-12-17  Python部落    Tags:   点击:(9)  评论:(0)  加入收藏
新京报快讯 据中国网络视听节目服务协会网站消息,12月15日,中国网络视听节目服务协会发布了《网络短视频内容审核标准细则》(2021)。中国网络视听节目服务协会组织有关短视频平...【详细内容】
2021-12-16    新京报  Tags:短视频   点击:(11)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条