读完本节内容,你可以知道:
- 同源策略产生的原因和作用;
- 跨域的多种解决方案。
前言
我们可以设想这样一个场景:
学校开放了一个窗口给家长,让家长可以通过窗口询问孩子的成绩。班级里面的每个学生都是互不相关、互不影响的个体,每个学生和家长都来自同一个家庭。当同一个家庭里面的家长询问孩子的成绩,窗口就会给出相应的数据。如果不同家庭的家长来询问其他学生的成绩,窗口都给出应答,这样孩子成绩的安全性就没法得到保证。这样不就乱套了吗?
1. 如果没有同源策略
首先,让我们来看看上面例子中的窗口、家庭、家长、学生在Web世界中的对应关系:
这个窗口就是浏览器的窗口,里面的家长和学生就是一个个独立的网站,而每个家庭就是同域。
如果Web世界没有安全策略,那么我们的网站可以加载并执行其他网站的任意文件,这样将会出现很多不可控的问题。
比如打开一个银行站点,然后又不小心打开了一个恶意站点,如果没有安全措施,恶意站点就可以做很多事情:
- 修改银行站点的
DOM、CSSOM等信息; - 在银行站点内插入恶意
JavaScript脚本; - 劫持用户登录的用户名和密码;
- 读取用户的
Cookie、IndexDB等数据; - ...
2. 同源策略
那么如何保证只有同一个家庭里的家长才能查询学生的成绩呢?对应Web世界里,如何保证网页只能被同一个域中的代码查询、修改呢?
这就有了我们今天的主角:同源策略(Same-origin policy)。
同源策略是一种约定,它是浏览器最核心也最基本的安全功能 ... 可以说Web是构建在同源策略的基础之上的,浏览器知识针对同源策略的一种实现。
来自《白帽子讲Web安全》
2.1 什么是同源
如果两个URL的协议(protocol)、端口(port)、域名(host)都相同的话,那么这两个URL就是同源的。
下表给出了与URL store.company.com/dir/page.ht… 的源进行对比的示例:
| URL | 结果 | 原因 |
|---|---|---|
| store.company.com/dir2/other.… | 同源 | 只是路径不同 |
| store.company.com/dir/inner/a… | 同源 | 只是路径不同 |
| store.company.com/secure.html | 不同源 | 协议不同 |
| store.company.com:81/dir/etc.htm… | 不同源 | 端口不同 ( http:// 默认端口是80) |
| news.company.com/dir/other.h… | 不同源 | 主机不同 |
2.2 同源策略的作用
从上面的例子我们知道,同源策略的作用就是限制来自另一个域的资源的交互,从而保障我们网站的隐私和数据的安全。
2.3 同源策略的表现
具体来讲,同源策略主要表现在三个层面:DOM、Web数据、网络数据。
DOM层面。同源策略限制了来自不同源的JavaScript脚本对当前页面的DOM对象进行读写操作,从而防止跨域脚本篡改DOM结构。
数据层面。同源策略限制不同源的站点读取当前站点的Cookie、LocalStorage和IndexDB数据,从而保障数据的安全性。
网络层面。同源策略限制了通过XMLHttpRequest等方式将站点的数据发送给不同源的站点。
2.4 跨域可行性的表现
跨域可行性的表现主要是在两个层面:HTML标签、数据的读写。
标签层面。<script>、<img>、<iframe>、<link>、<video>、<audio>带有src属性的标签可以跨域访问。
使用HTML实现跨域访问时,程序员自行判断站点的安全性。
读写层面。表单提交或者重定向请求允许跨域写操作。
3. 跨域的解决方案
jsonp
document.domain
location.hash
windown.name
postMessage
跨域资源共享(CORS)
Nginx代理
Node.js中间件代理
WebSocket协议
4. 总结
| 跨域方式 | 原理 | 缺点 | 适用场景 |
|---|---|---|---|
| jsonp | 只支持get请求 | 加载不同域名的静态资源文件 | |
| CORS | 做Ajax各种跨域请求 | ||
| Nginx代理 or Node.js代理 | 前后端分离的前端项目调用后端接口 | ||
| document.domain | 主域名相同,子域名不同的跨域请求 | ||
| postMessage | |||
| Websocket |