你的位置:首页 > Java教程

[Java教程]对同源策略与多页面通讯、跨域请求的深入探索



为了网页的安全,现在主要的浏览器都遵循了同源策略。同源策略究竟有哪些规范?怎么体现安全作用?
个人总结同源策略的一个首要宗旨是:

阻止能向外传输信息的模块(如javascript)获取到来自不同源的资源,不能获取也就从源头阻止了资源和其中信息的泄露

很重要的一点是,同源策略阻止的是跨域资源的获取,而不是阻止跨域的请求,请求可以正常发出,但返回的内容被阻止,无法让JS脚本获取


针对javascript,且看几个直观的现象:
1、一个页面的javascript能获取到其他页面的window。但在非同源的情况下,只能访问window少部分属性和方法。
不同源时可访问属性方法如下:
方法
window.blur
window.close
window.focus
window.postMessage
属性
window.closed   Read only.
window.frames  Read only.
window.length   Read only.
window.location Read/write.
window.opener  Read only.
window.parent   Read only.
window.self       Read only.
window.top       Read only.
window.window Read only.
有一些浏览器也许会允许访问更多一些属性方法。但重要的document,localstorage等肯定是无法读写的。
页面可以自身设置document.domain,开放其他一部分域的脚本对自身document、localstorage等的读写。
在同源的基础下,则没有限制。
2、<script>、<img>、<iframe>、<link>等标签都能跨域加载内容,但无法利用这些标签对外发送加载到的内容。
3、js脚本不能获取到上述标签加载回来的内容,也就无法把这些内容发送出去,只能获取到内容被浏览器解析后浏览器基于需要而暴露的信息(如img的width,onload等)。

一个不直观的现象:
1、ajax可以利用用户身份请求不同源的内容,但同源策略阻止了请求回来的内容向javascript的流通,于是无法泄露到用户浏览器之外。

这个现象可以自己架设localhost试验,后台正常收到请求并正常回应,但是浏览器出显示没有跨域资源共享,无法访问返回的内容

怎么体现安全作用?
设想一个场景,用户打开www.bank.com/bank.html, 又在另一个标签里打开 www.evil.com/evil.html。
此时在同源策略下,evil.html页面上的js脚本不能访问操作bank.html页面的document,localstorage等重要资源。
evil.html可以利用脚本创建iframe,img,script去加载bank.com的资源,这些资源加载回来后由浏览器默认的去解析或呈现,脚本依然无法获取加载回来的内容,只能得到浏览器基于需要而暴露的信息(如img的width,onload等)。
evil.html的脚本可以利用Ajax直接去加载bank.com上的资源,Ajax请求可以正确发出并返回,但停在了浏览器处,同源策略阻止了请求回来的内容向evil.html上脚本的流通
至此evil.html的脚本关于用户的信息都无法获取到。
特别地,从bank.html或者evil.html发送请求到bank.com/charge.html,
两者携带的cookie是同样的,不同的是http请求头的referer,后端只判断cookie/session的话就会认为都是真正用户的请求。于是就形成了跨域请求伪造攻击(CSRF)。
对此,bank.com后端不傻,它事先发送了唯一标识在bank.html的页面上,bank.html到charge.html的请求还带上了唯一标识,后端不仅判断referer,还特意去检查收到的标识和事先发送的唯一标识是否一致。
evil.html无法访问bank.html,于是无法得到唯一标识,于是无法伪造和bank.html发出的一样的请求。
至此evil.html的脚本一无所获,无法获取并泄露信息也无法伪造请求。

综合以上现象,可以总结出,同源策略规范了javascript所能获取的资源和信息,所以用户即使不小心浏览到不良网页,也还有一定的安全性。

同源策略下,javascript对多页面之间的通讯和多个域的资源获取都受到了限制,下面简要介绍在同源策略下一些合理跨域的方法
对于多页面通讯
1、设置document.domain+iframe
2、window.name
3、window.postMessage,window.localstorage
对于跨域资源获取
4、跨域资源共享CORS(Cross-Origin Resource Sharing)
5、JSONP
6、WebSockets
总结是这些方法都是A去访问B, B页面主动开放访问权限,或者B服务器自己根据请求信息判断是否对A请求开放并配合A返回合适的响应,于是A可以跨域获取资源。
个人觉得后台代理的方式对前端来说并没有跨域,所以就没有归结到上面的跨域方法中。


参考文章和跨域方法的详细介绍请参见以下文章:
JavaScript跨域总结与解决办法 http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html
Web - JSONP和同源策略漫谈 http://www.cnblogs.com/huangjacky/p/4001073.html
(译)同源策略和跨域访问 http://blog.csdn.net/shimiso/article/details/21830313
同源策略详解及绕过 http://www.freebuf.com/articles/web/65468.html
浏览器同源政策及其规避方法 http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

有兴趣的可以看看关于同源策略比较官方的介绍
w3c: https://www.w3.org/Security/wiki/Same_Origin_Policy
wiki: https://en.wikipedia.org/wiki/Same-origin_policy
MDN: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy