浏览器系列 - 浏览器才有"同源策略"吗?

241 阅读6分钟

本文首发于 SwainWong 的博客 传送门👉👉👉

🌈 记录总结日常工作学习...欢迎star....

前言

实习时第一次接触浏览器同源策略问题,是前后端准备联调需要访问后端Api,呆头呆脑的我再浏览器上发送了好久的 xhr 请求,却一直不成功.....头都麻了 一起实习的小伙伴让我在Chrome的启动程序上,加上--disable-web-security的小尾巴禁用掉同源策略,轻松加愉快地直接解决了问题......

作为web开发者,工作中不同阶段、不同场景都会遇到跨域的情况。这篇笔记📒在博客中也随着工作学习的推进,一次次地更新内容,更新自己对跨域这一问题的认识。

以下内容最后更新于2020.10,前文内容略有删改。由于这个问题体系比较繁杂,本片文章仅涉及

  • 浏览器同源策略的由来
  • 为什么要同源策略,不设置会有什么安全问题。
  • 为什么客户端没有同源策略呢
  • 一些特殊的跨域场景

想了解项目中如何进行跨域设置的小伙伴,请关注下一篇文章。

浏览器的同源策略

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

同源定义

资源URL的以下三项中都相同时才认为两个资源是同源的

  • 协议: 比如http、https、ws、wss
  • 域名: 包括主域名和子域名,需要做到全匹配。
  • 端口号

非同源数据存储访问

  • localStorageIndexedDB 是浏览器常用的本地化存储方案,两者都是以源进行分割。每一个源下的脚本,都只能够访问同源中的缓存数据,不能实现跨域访问。
  • Cookie的匹配规则与上面二者又略有差异,主要差异在于子域cookie会默认使用在父域上。详细的规则可以参考另一篇笔记 浏览器原理 - 缓存之cookie
  • DOM 如果两个网页不同源,就无法拿到对方的DOM。 比如项目中制作的Telegram登录,授权Button是一段插入<Iframe>的脚本。Ifream本身的域名是auth.telegram.io。那么域名为abc.io的业务页面,则不能Ifream中的DOM进行访问。

网络资源限制

  • 除了图片cssjs资源外,无法通过网络请求访问不同域的资源
  • 能够通过JSONPCORSWebsocket的形式进行。
  • SOP 本质上 SOP 并不是禁止跨域请求,而是浏览器在请求后拦截了请求的回应

为什么只有浏览器有同源策略

浏览器是个公共应用

无论是在PC还是移动设备商,你的 Chrome 和 Firefox 是所有网站应用的载体。

你在访问 淘宝网 的时候,相当于从 www.taobao.com 的服务器上下载了 对应的 html、css、js资源,页面也从 api.taobao.com (JSONP 也好, CORS 也罢)获取了商品数据。

页面 JavaScript 把获取到的热门商品数据 缓存到了 本地的 localstorage 中,用于优化体验。

你点击登陆时,通过访问 api.taobao.com/login 接口完成了授权登录,服务器下发 Token 到 cookie 中。

同样的,在京东、在亚马逊、在你的个站、甚至在恶意网站进行访问后,网站的数据都会被下载到设备本地,并且通用 浏览器 这一个应用所管理着。

资源以域划分,是浏览器的本地行为

接触过客户端的同学一定知道,在安卓 和 iOS上的两个App的本地数据,没有对方的允许是不能够直接本访问的,控制权在于App开发方本身,而提供保障的则是系统(Android 和 iOS)本身。 相同的情况类比一下,把浏览器当做系统本身(Chrome Book 请给我打钱),把各个站点相当于“系统上”的一个个App。

下面的页面各位 FEer一定很熟悉,这是Chrome浏览器对于页面中所有加载的静态资源的域名划分。

Chrome 浏览器静态资源预览

想想一下,不仅仅是静态的资源。WebStorage、Cookie、IndexDB,在浏览器层面上都是以域这一概念来划分管理的。而且这个划分管理行为,就是在浏览器本地生效,和服务器、其他客户端没有直接关系。

浏览器不会阻断跨域请求

你在 your.company.com 对 data.abc.com 发起数据请求,通常我们会遇到浏览器跨域访问的提示,你的代码拿不到 返回的数据。

但其实对于跨域请求,浏览器并不是直接阻止了此次请求的发出,也没有隔断数据的返回。仅仅是阻止了你尝试跨越 “域” 这个本地 “沙箱” 去访问其他域 下刚刚获取回来的数据 罢了。

你的业务代码在 your.company.com 域下,请求回来的数据在 data.abc.com 域下,是不是?

你品品,你再品

跨域 与 服务器响应头

在以前的理解中,我们总容易把跨域想想得跟服务端有很大关系,因为服务端总是要去设置什么 Access-Control-Allow-Origin 巴拉巴拉的好几个响应头(我猜你已经熟读全文,并能够默写了)。

总的来说,我们要将 页面HTML 脚本 样式 字体 等静态资源,和接口返回的数据都同等视为资源,而资源在浏览器的管理下,就是以域区划分管理的。

在同源策略中,<img> <script> 不受跨域访问限制 (熟悉的 打点上报JSONP),是因为浏览器本地开放了这些途径返回的资源的访问权限。

而我们常见的 跨域响应头 们,相当于告诉了浏览器,这几个资源的管理权限应该 根据跨域响应头 来设置,所以本地的其他域下的 JavaScript 代码才能够访问得到这些返回的数据。

小结

  1. 无论是同步请求、异步请求返回的,要都将所有服务器返回的内容都视为资源,都受浏览器统一管理浏览器与域来划分着所有它管理的资源
  2. 浏览器发现请求跨域时,并不会阻止请求的发出与响应通路
  3. 同源策略 是一个w3c提出,各大浏览器厂实现的一个策略。一个域中的JavaScript代码,尝试访问另一个域中的任何资源时,都要通过浏览器的同源策略检测。
  4. 把浏览器考虑成 Android 或 iOS 平台本身,这个问题就能够解释得通了。

Todo

  • 补充客户端跨APP访问资源的资料
  • 补充 RFC 对浏览器 同源策略的定义

参考资料

[1] 浏览器的同源策略 - MDN
[3] CORS - MDN