先来看一下官方的解释:同源策略是对Javascript代码能够操作哪些Web内容的一条完整的安全限制。当一个页面嵌入一个或者多个iframe元素或者打开其他浏览器窗口的时候,这一策略通常就会发挥作用,具体来说,脚本只能读取和所属文档来源相同的窗口和文档的属性。
什么是来源?
文档的来源包含协议、主机,以及载入文档的URL端口。从不同Web服务器载入的文档具有不同的来源。通过同一主机的不同端口载入的文档具有不同的来源。使用http:协议载入的文档和使用https:协议载入的文档具有不同的来源,即使它们来自同一个服务器;
举个例子:http://a.example.com和https://a.example.com不是同源
这里特别要强调下,脚本本身的来源和同源策略并不相关,这个源指的是文档的来源,通俗点就是html文件,而不是说脚本的来源,比方说我们经常用到的框架vue,在页面-http://a.example.com-(以下简称a页面或者a文档)中这么引入
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>
虽然这个脚本的来源是cdn.jsdelivr.net,和a文档毫无关系,但是它可以完整地访问包含它的文档的内容。如果脚本打开一个新窗口并载入另外一个a文档,脚本对这个文档的内容也具有完全的访问权限。但是,如果脚本打开第三个窗口并载入一个b文档(http://b.example.com),同源策略就会发挥作用,阻止脚本访问这个文档。
这里介绍下访问自己打开的文档是什么意思,大家都知道打开一个页面可以用window.open方法,而该方法有一个返回值,返回的是所打开窗口的window对象,这样就有入口了,还是以上面的a文档,b文档为例,首先在a文档调用
var a2_window = window.open('http://a.example.com')
console.log(a2_window.document)
可以看到能够访问到document对象,因为是同源,再来一个:
var b_window = window.open('http://b.example.com')
console.log(b_window.document)
可以看到明显的跨域提示
另外对于内嵌的iframe元素也是同样道理,怎样获取iframe的window对象?其实也简单的,方法有很多,我给出一种:
var f1_window = document.getElementById('f1').contentWindow
至于上面我自定义的a,b两个文档,大家本地也可以测试的,我使用nginx配置的,大家也可以用其他方法。
除了限制访问文档外,同源策略还应用于使用XMLHttpRequest生成的HTTP请求,这个对象允许客户端JavaScript生成任意的HTTP请求到脚本所属文档的Web服务器,但是不允许脚本和其他Web服务器通信。也就是说a文档向b文档发送一个http请求就是跨域了,会限制:
var request = new XMLHttpRequest()
request.open("GET","http://b.example.com/users");
request.send(null);
也是提示跨域了
好了,相信大家一定知道同源策略的重要性,如果没有这一限制,恶意脚本(通过防火墙载入到安全的公司内网的浏览器中)可能会打开一个空的窗口,欺骗用户进入并使用这个窗口在内网上浏览文件。恶意脚本就能够读取窗口的内容并将其发送回自己的服务器。同源策略防止了这种行为。
但是在某些情况下,同源策略就显得太过严格了。接下来我会向大家介绍三种不严格的同源策略
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。