浏览器的同源策略
同源策略
什么是同源简介
同源既是协议、域名、和端口三者相同,下面相对http://store.company.com/dir/page.html同源检测的示例。
浏览器中的大部分内容都是受同源策略限制的,但是以下三个标签可以不受限制
<img src=XXX>
<link href=XXX>
<script src=XXX>
为什么要有同源策略
如果不会操作的来源进行验证,那么不同源的数据和资源(如HTTP头、Cookie、DOM、localStorage等)就能相互随意访问,根本没有隐私和安全可言。
同源策略是为了保证用户信息的安全,防止恶意的网站窃取数据。
一些具体的同源策略
DOM
同源:禁止对不同源页面DOM进行操作
通过上图我们可以看到DOM
可以直接获取到cookie信息,如果不对操作DOM的行为作出约束这将是很可怕的。对操作DOM的限制也是同源的三个方面,协议、DNS域名和端口号。
同源策略
-
如果交互页面的协议、主机名和非 Internet Explorer 端口号的浏览器匹配,则无需进一步检查即可访问
-
任何页面都可以将
document.domain
参数设置为其当前主机名的右侧完全限定的片段,比如foo.bar.example. com
可以将其设置为example.com
,也可以为bar.example.com
。如果两个页面显式且相互将各自的document.domain
参数设置为相同的值,并且满足了其余的同源检查,则允许访问
示例
百度网盘和百度搜索是不同的domain
CSDN下载和CSDN博客是相同的domain
(在同源策略中,domain和中文的域名可能有些区别,需要注意一下)
通过上图结合同源策略,我们可以得出如下结论:
- 百度搜索和百度网盘两个站点不能满足DOM同源
- CSDN的下载和博客站点是可以通过的
对DOM同源策略的"攻击"
下面的代码实在我自己创建的html界面中访问网易的DOM,按钮xqh
是触发访问的按钮
结果如下
Cookie
同源
为什么要有cookie
HTTP是不保存状态的协议,这是为了更快的处理大量事务,确保协议的可伸缩性,但是在一些情况下需要保持登录状态。而我们在真实世界中对网站的大部分访问是需要有登录这个状态的,方便服务提供方为我们提供一些有针对性的定制服务。
下面是google给我的cookie
Cookie
存在的问题
- Cookie数量和长度的限制。
- 长度太短容易被**
-
Cookie劫持问题。如果cookie被人拦截了,那人就可以取得所有的会话信息。(
Cookie
主要来解决这么一个事)- 比如我在访问较为较为私密的网站时,同时不小心浏览了恶意网站,如果同源策略做的不好的话,我私密网站的cookie就可能被盗取。
Cookie的同源策略
- 一般的同源策略:需要满足:协议 域名 端口,而cookie的"同源策略:仅仅关注domain
-
Cookie
的作用域- Domain 告诉浏览器当前要添加的Cookie 的域名归属
- Path 告诉浏览器当前要添加的Cookie的路径归属
- 浏览器提交的Cookie需要满足以下两点
- 当前域名或者父域名下的Cookie
- 当前路径或父路径下的Cookie
- 可以参考上面google的那张图,
google.com
是www.google.com
的父域名
cookie的实例
百度网盘和百度搜索不是同一个cookie,因为他们domain不一样
CSDN的下载和blog的cookie相同,因为他们的domain相同
XMLHttpRequest
同源:禁止向不同源的地址发起HTTP请求
同源策略
由于通过 XMLHttpRequest
发送的所有请求都包含一组用于目标站点的浏览器维护的 cookie,而且考虑到该机制提供的与服务器端组件交互的能力远远超过脚本可用的任何其他特性,因此建立适当的安全控制极为重要。
- 对
XMLHttpRequest
目标的检查不考虑document.domain
,这使得第三方站点不可能相互同意允许它们之间的跨域请求 - 在一些实现中,对于协议、头字段和 HTTP 方法(其功能可用)或 HTTP 响应代码(将显示给脚本)有附加的限制(见后面)
- 在 Internet Explorer 中,尽管端口号在进行“正确的” DOM 访问同源检查时没有考虑在内,但是在
XMLHttpRequest
中考虑在内
何时需要跨域请求
跨域请求既是该请求不满足同源要求
需要跨域的一些情况
- 使用
cdn
加速服务 - 博客中使用图床
-
fetchAPI
通过跨站点⽅式访问资源,⽹络字体,例如Bootstrap(通过CSS使⽤@font-face 跨域调⽤字体) - 通过canvas标签,绘制图表和视频
- DOM操作,同源策略禁⽌对不同源⻚⾯ DOM 进⾏操作。这⾥主要场景是
iframe
跨域的情况,不同域名的iframe
是限制互相访问的
对同源策略的一些改变
本来想用改进这个词,但是觉得这还像是安全性向便捷性妥协的一种,还是用对这种策略的改变好一些
由于对 document.domain
的排除使得通过 XMLHttpRequest
进行任何类型的客户端跨域通信都成为不可能,作为一个需求量很大的扩展,W3C 提出的跨域 XMLHttpRequest
访问控制将允许在某些附加条件下发生跨站点通信。建议者提出的方案如下:
-
基于 GET 流量不会改变服务器端应用程序状态,因此不会产生持久的副作用这一假设,带有限制为白名单的自定义头的 GET 请求将立即发送到目标系统,而不需要事先验证。按照 RFC 2616中阐明的”不应该”建议,这一假设在理论上是合理的,但在实践中很少得到遵守。但是,除非响应中出现适当的 HTTP 头或 XML 指令,否则不会向请求者显示结果
-
非 GET 请求(POST 等)之前会有一个“预飞行” OPTIONS 请求,同样只允许有白名单标头。除非在响应中看到适当的 HTTP 头或 XML 指令,否则不会发出实际的请求
绕过
XMLHttpRequest
同源策略的一种常见攻击是CRSF(Cross site request forgery)
CSRF(Cross site request forgery),即跨站请求伪造。我们知道XSS是跨站脚本攻击,就是在用户的浏览器中执行攻击者的脚本,来获得其cookie等信息。而CSRF确实,借用用户的身份,向web server发送请求,因为该请求不是用户本意,所以称为“跨站请求伪造”。
一般而且存在XSS漏洞的网站,也极有可能存在CSRF漏洞。因为CSRF攻击中的那个“伪造的请求”的URL地址,一般是通过XSS攻击来注入到服务器中的。所以其实CSRF是以XSS为基础的,也可以看做是XSS攻击的一种。
CSRF一般的攻击过程是,攻击者向目标网站注入一个恶意的CSRF攻击URL地址(跨站url
),当(登录)用户访问某特定网页时,如果用户点击了该URL,那么攻击就触发了,我们可以在该恶意的url
对应的网页中,利用 来向目标网站发生一个get请求,该请求会携带cookie信息,所以也就借用了用户的身份,也就是伪造了一个请求,该请求可以是目标网站中的用户有权限访问的任意请求。也可以使用javascript
构造一个提交表单的post
请求。比如构造一个转账的post请求。
所以CSRF的攻击分为了两步,首先要注入恶意URL地址,然后在该地址中写入攻击代码,利用 等标签或者使用Javascript
脚本。
一个攻击示例
(来源:浅谈CSRF攻击方式)
对于复现crsf
攻击这个事我偷懒了,感兴趣的话可以看一下这个视频CSRF 攻击和防御 - Web 安全常识
(放一个坑在这,有时间自己复现一下啊啊啊)
如果看了这个视频的话我想很多人都会有疑问,为什么在登录之后我跨域请求直接就附带了cookie呢,也就是说为什么up主并没有特意去获取cookie却实现了crsf
呢,这其实就和前面cookie同源策略联系起来了,cookie同源只关注domain,而这里恰好都是localhost,所以在请求时,这里就直接把cookie捎带走了。
DNS REBIND
上面的例子局限性很大,只能相同的localhost,所有我们有了更为高明的攻击手段。
同源策略中,有一条是要求domain相同,但是相同的domain不一定是相同的IP呀!所以这就是攻击的点,通过给相同的domian绑定不懂的IP地址来完成CRSF
。
DNS REBIND 用一句话来说就是,利用DNS记录的TTL有限这一特定,将TTL设置到较小的状态,这时客户端就需要在每次和某个域名服务器交互时,就需要发送DNS请求,先将域名解析到正确的IP,再解析到错误的网址,然后我们就获得了victim的cookie
同源限制了一定的便捷性
安全性和方便性是成反比的,同源策略提升了Web前端的安全性,但牺牲了Web拓展上的灵活性。设想若把html、js、css、flash,image等文件全部布置在一台服务器上,小网站这样凑活还行,大中网站如果这样做服务器根本受不了的,可用性都不能保证的话。所以,现代浏览器在安全性和可用性之间选择了一个平衡点。在遵循同源策略的基础上,选择性地为同源策略“开放了后门”。 例如img script style等标签,都允许垮域引用资源,严格说这都是不符合同源要求的。然而,只能是引用这些资源,不能读取这些资源的内容。
比如jQuery
、vue
这些封装好的框架允许我们在线引用。
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/aaa@qq.com/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/aaa@qq.com/dist/vue.min.js"></script>