为何使用同源策略?
一个重要缘由就是对cookie的保护,cookie 中存着sessionID 。若是已经登陆网站,同时又去了任意其余网站,该网站有恶意JS代码。若是没有同源策略,那么这个网站就能经过js 访问document.cookie 获得用户关于的各个网站的sessionID。其中可能有银行网站,经过已经创建好的session链接进行攻击,这里有一个专有名词,CSRF,还有须要注意的是同源策略没法彻底防护CSRF,这里须要服务端配合。javascript
什么是同源策略?java
URL由协议、域名、端口和路径组成,若是两个URL的协议、域名和端口相同,则表示他们是同源的。同源策略是浏览器上为安全性考虑实施的很是重要的安全策略。限制来自不一样源的"document",对当前"document"读取或设置某些属性。 在浏览器中,<script>、<img>、<link>、<frame>等标签均可加载跨域资源,而不受同源策略限制,这带"src"属性的标签加载时,其实是由浏览器发起一次GET请求,不一样于XMLHttpRequest,他们经过src属性加载的资源。但浏览器限制了JavaScript的权限,使其不能读、写其中返回的内容。程序员
跨域请求的安全基础是,JavaScript没法修改请求对象的http头部。 若是XMLHttpRequest可以跨域请求资源,可能致使敏感信息泄露,好比CSRF的token信息,跨域
受同源策略限制的有哪些?浏览器
DOM、Cookie、XMLHttpRequest,还有一些第三方插件Flash、Java Applet、Sliverlight、Google Gears等都有本身的控制策略。安全
如何规避同源策略,即跨域请求?服务器
document.domain属性cookie
若是两个window或者frames包含的脚本能够把domain设置成同样的值,那么就能够规避同源策略,每一个window之间能够互相沟通。例如,orders.example.com下页面的脚本和catalog.example.com下页面的脚本能够设置他们的document.domain属性为example.com,从而让这两个站点下面的文档看起来像在同源下,而后就可让每一个文档读取另外一个文档的属性。这种方式也不是一直都有用,由于端口号是在内部保存的,有可能被保存成null。换句话说,example.com的端口号80,在咱们更新document.domain属性的时候可能会变成null。为null的端口可能不被认为是80,这主要依赖浏览器实现。session
跨域资源共享(CORS) app
Cross-origin Resource Sharing跨资源共享,使用自定义的HTTP头部让浏览器与服务器沟通,从而决定请求和响应是否成功。这种方式使用了一个新的Origin请求头和一个新的Access-Control-Allow-Origin响应头扩展了HTTP。容许服务端设置Access-Control-Allow-Origin头标识哪些站点能够请求文件,或者设置Access-Control-Allow-Origin头为"*",容许任意站点访问文件。
浏览器,例如Firefox3.5,Safari4,IE10使用这个头容许跨域HTTP请求。
服务器端在HTTP的响应头中加入(页面层次的控制模式):
Access-Control-Allow-Origin: example.com
Access-Control-Request-Method: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Range, Origin
Access-Control-Expose-Headers: Content-Range
Access-Control-Max-Age: 3600
多个域名之间用逗号分隔,表示对所示域名提供跨域访问权限。"*"表示容许全部域名的跨域访问
客户端能够有两种行为:
1. 发送OPTIONS请求,请求Access-Control信息。若是本身的域名在容许的访问列表中,则发送真正的请求,不然放弃请求发送。
2. 直接发送请求,而后检查response的Access-Control信息,若是本身的域名在容许的访问列表中,则读取response body,不然放弃。 本质上服务端的response内容已经到达本地,JavaScript决定是否要去读取。
跨文档通讯(window.postMessage方法)
这种方式容许一个页面的脚本发送文本信息到另外一个页面的脚本中,无论脚本是否跨域。基本上,它就像是跨域的AJAX,但不是浏览器跟服务器之间交互,而是在两个客户端之间通讯。在一个window对象上调用postMessage()会异步的触发window上的onmessage事件,而后触发定义好的事件处理方法。一个页面上的脚本仍然不能直接访问另一个页面上的方法或者变量,可是他们能够安全的经过消息传递技术交流。
容许程序员跨域在两个窗口/frames间发送数据信息。
窗口A: 发送窗口使用postMessage发送数据 window.postMessage(msg,urlOfB); 窗口B: 接收端,监听“message”事件,
window.onmessage(event){ var data=event.data; var origin=event.origin; }
JSONP
JSONP利用<script>标签的跨域能力实现跨域数据的访问,请求动态生成的JavaScript脚本同时带一个callback函数名做为参数。其中callback函数本地文档的JavaScript函数,服务器端动态生成的脚本会产生数据,并在代码中以产生的数据为参数调用callback函数。当这段脚本加载到本地文档时,callback函数就被调用。
为了动态实现JSONP请求,可使用Javascript动态插入<script>标签:
<script type="text/javascript"> // this shows dynamic script insertion var script = document.createElement('script'); script.setAttribute('src', url); // load the script document.getElementsByTagName('head')[0].appendChild(script); </script>
WebSocket
现代浏览器容许脚本直连一个WebSocket地址而无论同源策略。然而,使用WebSocket URI的时候,在请求中插入Origin头就能够标识脚本请求的源。为了确保跨站安全,WebSocket服务器必须根据容许接受请求的白名单中的源列表比较头数据。 与JSONP方法不一样的是,该响应函数被传入到建立<script> 标签的构造函数中,检测到已经成功接受到收据的状态后再执行函数。
document.domain + iframe (只有在主域相同的时候才能使用该方法)
location.hash + iframe
window.name + iframepostMessage(HTML5中的XMLHttpRequest Level 2中的API)