## 同源策略  

同源策略（Same Origin Policy）是一种约定，它是浏览器最核心也最基本的安全功能，如果缺少了同源策略，则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略的基础之上的，浏览器只是针对同源策略的一种实现。  

对于客户端Web安全的学习与研究来说，深入理解同源策略是非常重要的，也是后续学习的基础。很多时候浏览器实现的同源策略是隐性、透明的，很多因为同源策略导致的问题并没有明显的出错提示，如果不熟悉同源策略，则可能一直都会想不明白问题的原因。  

浏览器的同源策略，限制了来自不同源的“document”或脚本，对当前“document”读取或设置某些属性。  

这一策略极其重要，试想如果没有同源策略，可能a.com的一段JavaScript脚本，在b.com未曾加载此脚本时，也可以随意涂改b.com的页面（在浏览器的显示中）。为了不让浏览器的页面行为发生混乱，浏览器提出了“Origin”（源）这一概念，来自不同Origin的对象无法互相干扰。  

对于JavaScript来说，以下情况被认为是同源与不同源的。  

浏览器中JavaScript的同源策略（当JavaScript被浏览器认为来自不同源时，请求被拒绝）  

由上表可以看出，影响“源”的因素有：host（域名或IP地址，如果是IP地址则看做一个根域名）、子域名、端口、协议。  

需要注意的是，对于当前页面来说，页面内存放JavaScript文件的域并不重要，重要的是加载JavaScript页面所在的域是什么。  

换言之，a.com通过以下代码：  

加载了b.com上的b.js，但是b.js是运行在a.com页面中的，因此对于当前打开的页面（a.com页面）来说，b.js的Origin就应该是a.com而非b.com。  

在浏览器中，<script>、<img>、<iframe>、<link>等标签都可以跨域加载资源，而不受同源策略的限制。这些带“src”属性的标签每次加载时，实际上是由浏览器发起了一次GET请求。不同于XMLHttpRequest的是，通过src属性加载的资源，浏览器限制了JavaScript的权限，使其不能读、写返回的内容。  

对于XMLHttpRequest来说，它可以访问来自同源对象的内容。比如下例：  

但XMLHttpRequest受到同源策略的约束，不能跨域访问资源，在AJAX应用的开发中尤其需要注意这一点。  

如果XMLHttpRequest能够跨域访问资源，则可能会导致一些敏感数据泄露，比如CSRF的token，从而导致发生安全问题。  

但是互联网是开放的，随着业务的发展，跨域请求的需求越来越迫切，因此W3C委员会制定了XMLHttpRequest跨域访问标准。它需要通过目标域返回的HTTP头来授权是否允许跨域访问，因为HTTP头对于JavaScript来说一般是无法控制的，所以认为这个方案可以实施。注意：这个跨域访问方案的安全基础就是信任“JavaScript无法控制该HTTP头”，如果此信任基础被打破，则此方案也将不再安全。  

跨域访问请求过程  

具体的实现过程，在本书的“HTML 5安全”一章中会继续探讨。  

对于浏览器来说，除了DOM、Cookie、XMLHttpRequest会受到同源策略的限制外，浏览器加载的一些第三方插件也有各自的同源策略。最常见的一些插件如Flash、Java Applet、Silverlight、Google Gears等都有自己的控制策略。  

以Flash为例，它主要通过目标网站提供的crossdomain.xml文件判断是否允许当前“源”的Flash跨域访问目标资源。  

以www.qq.com的策略文件为例，当浏览器在任意其他域的页面里加载了Flash后，如果对www.qq.com发起访问请求，Flash会先检查www.qq.com上此策略文件是否存在。如果文件存在，则检查发起请求的域是否在许可范围内。  

www.qq.com的crossdomain.xml文件  

在这个策略文件中，只有来自\*.qq.com和\*.gtimg.com域的请求是被允许的。依靠这种方式，从Origin的层面上控制了Flash行为的安全性。  

在Flash 9及其之后的版本中，还实现了MIME检查以确认crossdomain.xml是否合法，比如查看服务器返回HTTP头的Content-Type是否是text/\*、application/xml、application/xhtml $+$ xmlo这样做的原因，是因为攻击者可以通过上传crossdomain.xml文件控制Flash的行为，绕过同源策略。除了MIME检查外，Flash还会检查crossdomain.xml是否在根目录下，也可以使得一些上传文件的攻击失效。  

然而浏览器的同源策略也并非是坚不可摧的堡垒，由于实现上的一些问题，一些浏览器的同源策略也曾经多次被绕过。比如下面这个IE 8的CSS跨域漏洞。  

www.a.com/test.html：  

www.b.com/test2.html：  

在www.b.com/test2.html中通过@import加载了http：//www.a.com/test.html为CSS文件，渲染进入当前页面DOM，同时通过document.body.currentStyle.fontFamily访问此内容。问题发生在IE的  

CSS Parse的过程中，IE将fontFamily后面的内容当做了value，从而可以读取www.a.com/test.html的页面内容。  

在www.b.com下读取到了www.a.com的页面内容  

我们前面提到，比如<script>等标签仅能加载资源，但不能读、写资源的内容，而这个漏洞能够跨域读取页面内容，因此绕过了同源策略，成为一个跨域漏洞。  

浏览器的同源策略是浏览器安全的基础，在本书后续章节中提到的许多客户端脚本攻击，都需要遵守这一法则，因此理解同源策略对于客户端脚本攻击有着重要意义。同源策略一旦出现漏洞被绕过，也将带来非常严重的后果，很多基于同源策略制定的安全方案都将失去效果。  

## 浏览器沙箱  

针对客户端的攻击近年来呈现爆发趋势：  

2009年全年挂马网站状况趋势图  

这种在网页中插入一段恶意代码，利用浏览器漏洞执行任意代码的攻击方式，在黑客圈子里被形象地称为“挂马”。  

“挂马”是浏览器需要面对的一个主要威胁。近年来，独立于杀毒软件之外，浏览器厂商根据挂马的特点研究出了一些对抗挂马的技术。  

比如在Windows系统中，浏览器密切结合DEP、ASLR、SafeSEH等操作系统提供的保护技术，对抗内存攻击。与此同时，浏览器还发展出了多进程架构，从安全性上有了很大的提高。  

浏览器的多进程架构，将浏览器的各个功能模块分开，各个浏览器实例分开，当一个进程崩溃时，也不会影响到其他的进程。  

Google Chrome是第一个采取多进程架构的浏览器。Google Chrome的主要进程分为：浏览器进程、渲染进程、插件进程、扩展进程。插件进程如flash、Java，pdf等与浏览器进程严格隔离，因此不会互相影响。  

Google Chrome的架构  

渲染引擎由Sandbox隔离，网页代码要与浏览器内核进程通信、与操作系统通信都需要通过IPC channel，在其中会进行一些安全检查。  

Sandbox即沙箱，计算机技术发展到今天，Sandbox已经成为泛指“资源隔离类模块”的代名词。Sandbox的设计目的一般是为了让不可信任的代码运行在一定的环境中，限制不可信任的代码访问隔离区之外的资源。如果一定要跨越Sandbox边界产生数据交换，则只能通过指定的数据通道，比如经过封装的API来完成，在这些API中会严格检查请求的合法性。  

Sandbox的应用范围非常广泛。比如一个提供hosting服务的共享主机环境，假设支持用户上传PHP、Python、Java等语言的代码，为了防止用户代码破坏系统环境，或者是不同用户之间的代码互相影响，则应该设计一个Sandbox对用户代码进行隔离。Sandbox需要考虑用户代码针对本地文件系统、内存、数据库、网络的可能请求，可以采用默认拒绝的策略，对于有需要的请求，则可以通过封装API的方式实现。  

而对于浏览器来说，采用Sandbox技术，无疑可以让不受信任的网页代码、JavaScript代码运行在一个受到限制的环境中，从而保护本地桌面系统的安全。  

Google Chrome实现了一个相对完整的Sandbox：  

Google Chrome的Sandbox架构  

IE 8也采取了多进程架构，每一个Tab页即是一个进程，如下是IE 8的架构：  

IE 8的架构  

多进程架构最明显的一个好处是，相对于单进程浏览器，在发生崩溃时，多进程浏览器只会崩溃当前的Tab页，而单进程浏览器则会崩溃整个浏览器进程。这对于用户体验是很大的提升。  

但是浏览器安全是一个整体，在现今的浏览器中，虽然有多进程架构和Sandbox的保护，但是浏览器所加载的一些第三方插件却往往不受Sandbox管辖。比如近年来在Pwn2Own大会上被攻克的浏览器，往往都是由于加载的第三方插件出现安全漏洞导致的。Flash、Java、PDF、.Net Framework在近年来都成为浏览器攻击的热点。  

也许在不远的未来，在浏览器的安全模型中会更加重视这些第三方插件，不同厂商之间会就安全达成一致的标准，也只有这样，才能将这个互联网的入口打造得更加牢固。  
