跨域的理解

    jwolf 
971  0  0   2018-7-15 15:13


前言

       前后端分离的日常开发中,我们经常提起“跨域”,都知道需要代理ajax请求才能正常拉取接口数据,今天我们来细化一下跨域到底是怎么回事。


什么是跨域

当一个资源从与该资源本身所在的服务器不同的域或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。

比如我们在 https://demo.jwolf.cn 使用

<img src="https://pic.jwolf.cn/test.jpg" />

注意src中的域名跟页面所在域名不一致,二级域名不一致也算,尽管可以操作window.domain)标签加载一个图片,或是加载来自别的域的css样式(如bootstrap的一些公共库)都属于跨域; 从浏览器脚本内发起的跨源HTTP请求(可能是前后端分离遇到的最多的情况),往往是引起我们关注跨域的源头,这里就涉及到同源策略。


同源策略

如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源。

几个常见的例子:

  1. 不同协议 (包括 http 和 https)

  2. 不同端口 (页面使用默认80,请求资源端口81)

  3. 不同域名 (包括二级域名 https://a.jwolf.cn  http://b.jwolf.cn)

IE在这里有不同的意见:

当涉及到同源策略时,Internet Explorer 有两个主要的不同点 授信范围(Trust Zones):两个相互之间高度互信的域名,如公司域名(corporate domains),不遵守同源策略的限制。 端口:IE 未将端口号加入到同源策略的组成部分之中,因此 http://company.com:81/index.html 和http://company.com/index.html 属于同源并且不受任何限制


对我们开发联调过程影响比较大的一点是:

       出于安全的原因,同源策略控制了不同源之间的交互,尤其对脚本发起的http请求更为严格,如XMLHttpRequest(事实上,大多数库实现Javascript发起ajax请求都是基于这个,如vue的axio, jquery.$ajax), 利用这些方式请求不同域的资源时,浏览器会限制我们的对这个资源的获取:

  • 可能是限制了该请求数据的发出。对于 非 简单头部 第一次"预检"请求——options被否认的情况,MLHttpRequest对象的onerror回调函数会被回调,请求的数据就不会发出;

  • 也可能是能正常发出请求,但是返回的结果被浏览器拦截。对于 简单头部 服务器会返回相应的资源,但是浏览器发觉跨域,然后拦截了数据。


    除非使用CORS的方式,这并不是本文的重点,要了解CORS相关的知识,可以看看阮一峰老师的这篇文章




嵌入类标签允许跨域获取资源例子

  • <script src="..."></script> 标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。

  • <link rel="stylesheet" href="..."> 标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type消息头。不同浏览器有不同的限制。

  • 嵌入图片img标签。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...

  • video 和 audio 标签嵌入多媒体资源。

  • <object>, <embed> 和 <applet> 的插件。

  • @font-face 引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。

  • <frame> 和 <iframe> 载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。

        这些例子很可能成为CSRF攻击利用的载体,因为src会引起客户端浏览器发起一个“无感知”的http请求,而这个请求是允许跨域的,一旦本地浏览器已经存在了某个站点的cookie信息,这个“无感知”的http请求有可能完成一部分非用户意愿的操作。

写在最后

       通过上面可以理解到,web设计者控制跨域控制力度的程度,也是在找寻一个用户平滑使用和安全的一个平衡点。

原创文章,转载请保留出处(jwolf.cn)。



标签