浏览器同源策略与跨域问题的解决方案

1、浏览器的同源策略

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介

1.1.同源的定义

如果两个 URL 的 protocolport (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。这个方案也被称为“协议/主机/端口元组”,或者直接是 “元组”。(“元组” 是指一组项目构成的整体,双重/三重/四重/五重/等的通用形式)

下表给出了与 URLhttps://ims.blibee.com/#/produce/skuProduc的源进行对比的示例:

 

URL地址是否同源原因备注
https://abc.efg.com/#/menu/allMenu 同源 只有路径不同是同源的  
http://abc.efg.com/#/menu/allMenu 不同源 协议不同  
https://abc.efg.com:8888/#/menu/allMenu 不同源 端口不同  
http://xyz.efeaef.com/#/sysConfig 不同源 主机,域名均不同  
       

 

 

 

 

 

 

1.2源的继承和更改

在页面中通过 about:blank 或 javascript: URL 执行的脚本会继承打开该 URL 的文档的源,因为这些类型的 URLs 没有包含源服务器的相关信息。

满足某些限制条件的情况下,页面是可以修改它的源。脚本可以将 document.domain 的值设置为其当前域或其当前域的父域。如果将其设置为其当前域的父域,则这个较短的父域将用于后续源检查。

 

1.3跨源网络访问

同源策略控制不同源之间的交互,例如在使用XMLHttpRequest 或 <img> 标签时则会受到同源策略的约束。这些交互通常分为三类:

 

跨域写操作 一般是被允许的例如链接(links),重定向以及表单提交。特定少数的HTTP请求需要添加 preflight
跨域资源嵌入 一般是被允许(后面会举例说明)
跨域读操作 一般是不被允许的但常可以通过内嵌资源来巧妙的进行读取访问

 

 

 

 

 

可嵌入跨域资源的一些示例:

 

示例类型标签名备注
JavaScript脚本 <script> 标签嵌入跨域脚本。语法错误信息只能被同源脚本中捕捉到
样式文件 <link> 由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的 HTTP 头部 Content-Type
图片文件 <img> 支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...
视频文件 <video> 可以跨域访问或者播放视频资源
音频文件 <audio> 可以跨域访问或者播放音频资源
插件 <object>、 <embed> 和 <applet> 可以跨域访问插件
字体 @font-face 一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)
框架 <iframe> 可以跨域加载iframe载入的任何资源。站点可以使用 X-Frame-Options 消息头来阻止这种形式的跨域交互

 

 

 

 

 

 

 

 

 

1.4如何允许和禁止跨域访问

可以使用 CORS 来允许跨源访问。CORS 是 HTTP 的一部分,它允许服务端来指定哪些主机可以从这个服务端加载资源。

 

阻止跨域写操作,只要检测请求中的一个不可推测的标记(CSRF token)即可,这个标记被称为 Cross-Site Request Forgery (CSRF) 标记。你必须使用这个标记来阻止页面的跨站读操作。

阻止资源的跨站读取,需要保证该资源是不可嵌入的。阻止嵌入行为是必须的,因为嵌入资源通常向其暴露信息。

阻止跨站嵌入,需要确保你的资源不能通过以上列出的可嵌入资源格式使用。浏览器可能不会遵守 Content-Type 头部定义的类型

 

1.5同源策略限制类型

类型场景备注
DOM同源限制

浏览器中禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,

不同域名的 iframe 是限制互相访问的。

跨域访问的iframe中的DOM是读不到也无法更改的
XMLHttpRequest同源限制 浏览器中禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求  
存储同源限制 浏览器中禁止跨域访问cookie、localStorage、sessionStorage、indexedDB等web存储信息

其中cookie的设置与其他存储略有不同,置 cookie 时,

可以使用 DomainPathSecure、和 HttpOnly 标记来限定其可访问性

 

 

 

 

 

 

 

2、解决跨域的几种方式

解决跨域有以下方法:

 

序号方法名原理实现方式备注
1 降域

同源策略认为域和子域属于不同的域,

比如以下域名:

child1.a.com 与 a.com,
child1.a.com 与 child2.a.com

通过设置 document.domain='a.com',

浏览器就会认为它们都是同一个源。

想要实现以上任意两个页面之间的通信,

两个页面必须都设置documen.domain='a.com

  • 只能在父域名与子域名之间使用,且将 xxx.child1.a.com域名设置为a.com后,
    不能再设置成child1.a.com
  • 存在安全性问题,当一个站点被攻击后,另一个站点会引起安全漏洞
  • 这种方法只适用于 Cookie 和 iframe 窗口
2  JSONP跨域

就是动态创建<script>标签,然后利用<script>的 src 属性

不受同源策略约束来跨域获取数据

SONP 由两部分组成:回调函数 和 数据。

回调函数是用来处理服务器端返回的数据,

回调函数的名字一般是在请求中指定的。

而数据就是我们需要获取的数据,也就是服务器端的数据

  • 只支持 GET 请求
  • 由于是从其它域中加载代码执行,因此如果其他域不安全,很可能会在响应中夹带一些恶意代码。
  • 要确定 JSONP 请求是否失败并不容易。
  • 虽然 HTML5 给 script 标签新增了一个 onerror 事件处理程序,但是存在兼容性问题。
3 window.name跨域

window 对象有个 name 属性,该属性有个特征:即在一个窗口(window)的生命周期内,

窗口载入的所有的页面(不管是相同域的页面还是不同域的页面)都是共享一个 window.name 的。

 

每个页面对 window.name 都有读写的权限,

 window.name 是持久存在一个窗口载入过的所有页面中的,

并不会因新页面的载入而进行重置

只能用于iframe跨域
4 location.hash跨域 location.hash 方式跨域,是子框架具有修改父框架 src 的 hash 值,通过这个属性进行传递数据 更改 跨域iframe中的hash 值,页面不会刷新,但可以读取到参数 但是传递的数据的字节数是有限的,受到URL的长度限制,不同浏览器中不同
5 postMessage

window.postMessage(message,targetOrigin) 方法是 HTML5 新引进的特性,

可以使用它来向其它的 window 对象发送消息,无论这个 window 对象是属于同源或不同源

调用 postMessage 方法的 window 对象是指要接收消息的那一个 window 对象,

该方法的第一个参数 message 为要发送的消息,类型只能为字符串;

第二个参数 targetOrigin 用来限定接收消息的那个 window 对象所在的域,如果不想限定域,可以使用通配符 *

需要接收消息的 window 对象,可是通过监听自身的 message 事件来获取传过来的消息,

消息内容储存在该事件对象的 data 属性中。

6 WebSocket

WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。

该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

   
7 设置CORS资源共享

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制

详细过程可以参考阮一峰老师的文章:

http://www.ruanyifeng.com/blog/2016/04/cors.html

 
8 使用服务器代理

因为http请求在服务器与服务器之间是不存在同源策略的限制。所以在进行跨域AJAX请求是,

通常进行服务器代理的方式。实际上,大部分公司的业务都是这么做的,最出名的代理服务器就是

大名鼎鼎的Nginx。

在前端开发过程中,因为本地调试的前端域名通常是locahost,直接进行AJAZ请求,一般都会跨域,

前端框架实际上是搭建了本地的Nodejs服务,通过proxy设置,将本地的请求通过服务区转发,

实现了服务器代理的功能

htttp请求通过服务转发到实际请求的地址当中,这样就避免了直接访问服务造成的

   

 

 

posted @ 2020-05-10 15:24  曼施坦因  阅读(362)  评论(0编辑  收藏  举报