分享 “码农的自我修养” 之 同源策略

hiveer · 2017年01月19日 · 最后由 hiveer 回复于 2020年02月07日 · 3121 次阅读

最近在读 Rails 安全性相关的文章时,再一次接触了 “同源策略” 这个术语。当然不陌生,不然还怎么混,俗话说 “没吃过猪肉,至少见过猪跑嘛”!

可是真心讲,我并没有真正理解他的内涵。秉持着一颗孜孜不倦,求索不断的心,我开始了探索 “同源策略” 本质内涵之路。

起码看了 30+ 的文章,Google 表示我就这么多资源了……

最终我获得了一些想要的东西,但是对 “同源策略” 的理解也并没有完全透测,苦恼😖

下面就跟大家分享下我的所得吧! 这是我认为还有用的文章:

http://yincheng.site/cross-domain/comment-page-1#comment-3307

http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html

http://eleveneat.com/2015/05/22/Same-origin-policy-md/

http://bbs.csdn.net/topics/390716390

http://blog.csdn.net/shimiso/article/details/21830313

https://en.wikipedia.org/wiki/Same-origin_policy

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

Wiki 的解释:

In computing, the same-origin policy is an important concept in the web application security model. Under the policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin. An origin is defined as a combination of URI scheme, hostname, and port number.[1][2] This policy prevents a malicious script on one page from obtaining access to sensitive data on another web page through that page's Document Object Model.

Mdn 的解释:

The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin. It is a critical security mechanism for isolating potentially malicious documents.

百度的解释:

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

仔细研读之后发现百度的解释是屁话,Wiki 的解释不全面,而 MDN 话不多,但说的都是核心。

而我说的核心如是:document or script loaded from one origin; resource from another origin

下面分别解释这两个核心:

document or script loaded from one origin

Document怎么操作另外一个 origin 的资源呢?

借用阮一峰博文的例子:

父窗口下有一个 iframe 窗口,如果父窗口的 dom 想去拿 iframe 窗口的 dom 会报错,反之亦然:

document.getElementById("myIFrame").contentWindow.document
// Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.

上面命令中,父窗口想获取子窗口的 DOM,因为跨源导致报错。 反之亦然,子窗口获取主窗口的 DOM 也会报错。

window.parent.document.body // 报错

Script 怎么去操作另外一个 origin 的资源呢?

除了 Ajax 我还没找到其他的例子: 这是我自己做的一个实验,我启动一个 local server,然后通过 ajax 向我的 heroku 服务器发送请求:

<script>
    url = "https://daily-plan.herokuapp.com";
    document.cookie = "version=1;";
    $.ajax({
        method: "GET",
        url: url,
        xhrFields: {
          'withCredentials': true
        },
        success: function(data){
          document.write(data);
        }
    })
</script>

Error Message:

XMLHttpRequest cannot load https://daily-plan.herokuapp.com/. Redirect from 'https://daily-plan.herokuapp.com/' to 'https://daily-plan.herokuapp.com/plans' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

通过上面的两个例子我们可以引申出第二个要点: resource from another origin

什么算是一个 origin 的资源? 从之上的例子可以看出来,DOM 算是一类,Ajax 返回的数据算是一类 (这一类包含 DOM,当然也包含像是 JSON 格式的数据),还有一种这里没有举例的就是 Cookie。

关于 Cookie,上面 Ajax 的例子也同时验证了同源策略对 Cookie 的部分限制。

在我没有设置 'withCredentials': true 的时候,Ajax cross domain request 没有带任何的 cookie(local domain or heroku domain); 而设置之后同样的 request 带上了 heroku domain 下的 cookie。

还有一些比较亮眼的结论是:

同源策略并没有限制请求的发送,仅仅是阻隔了响应的获取(参见:http://yincheng.site/cross-domain/comment-page-1#comment-3307

在浏览器中,script, img, iframe, link 等标签都可以加载跨域资源,而不受同源限制,但浏览器限制了 JavaScript 的权限使其不能读、写加载的内容

我想说: 这目前是我整理得到的一些信息,以及自己的认识。我相信,肯定这不是全部。所以需要大家来完善下,帮助等多人理解这个关键的概念。毕竟,没有它我甚至不敢打开浏览器写这篇博文。

什么是 origin? 这个我感觉你的描述不是很正确。 origin 是源,源头的意思。也就是说同源策略的意思是你只能从同一个源头获取数据,当然要排除一些特殊的获取方式,如 img tag。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号