iframe跨域没有权限_浏览器同源策略及跨域(一)

什么是同源策略

同源策略最早是由Netscape提出的一种安全策略,目前所有支持JavaScript的浏览器都使用这个策略。

同源策略要求:客户端脚本在没有明确授权的情况下,不能读写不同源网址的数据和资源(如HTTP头、Cookie、DOM、localStorage等)。

同源策略只是一个规范,并不是强制要求,各大厂商的浏览器只是针对同源策略的一种实现。它是浏览器最核心也是最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

同源是指:

  • 域名相同
  • 协议相同
  • 端口相同

例:ziv.com

协议是 http://

域名是 ziv.com

端口是 80 (默认端口)

以下网址与 ziv.com的同源情况如:

http://www.ziv.com/pc/demo.html       同源

http://ziv.com/h5/demo.html           不同源 域名不同

http://www.ziv.com:81/h5/demo.html    不同源 端口不同

https://www.ziv.com/h5/demo.html      不同源 协议不同

同源策略的意义

当两个网址是非同源时,它们之间的交互会有以下限制:

  • Cookie、LocalStorage和IndexDB无法相互读取
  • DOM无法相互获取
  • AJAX请求不能发送

这些限制都是出于对安全的考虑,都是有必要的。比如,你登录了知乎账号,然后打开了另一个网站,这个网站上的JavaScript可以跨域读取你的知乎账号数据,那这样就毫无隐私可言。又比如,一个恶意网站嵌入了银行账号登录页面,如果没有同源限制,恶意网页的JavaScript就可以获取用户登录的用户信息,想象一下如果是这样后果是不是很严重。

当然,同源策略也会带来一些弊端,导致我们合理的用途也会受到影响。因此,在开发过程中,我们常常需要通过跨域来规避限制。

几种跨域的方法:

230ee85677a961b55ea1d79d0dbec134.png

document.domain

document.domain 可以用来得到当前网页的域名,同时市场上主流浏览器都支持domain可写,但是只能赋值为当前域名或者基础域名,如果赋值成当前域名的子域名就会报错。

如果两个网页一级域名相同,二级域名不同,则可以通过设置相同的document.domain实现cookie共享和iframe窗口(或window.open打开的窗口)与父窗口之间的通信。

比如,a网页是 http://a.ziv.com/a.html,b网页是http://b.ziv.com/b.html,然后设置它们的document.domain为:

document

那么,a网页设置的cookie,在b网页可以通过js拿到,同样b网页设置的cookie,在a网页也可以通过js拿到。它们的cookie是相互共享的。

如果在a网页通过iframe将b网页设置为a的子窗口:

<iframe id="iframe" src="http://b.ziv.com/b.html"></iframe>

那么,a、b窗口可以相互获得彼此的DOM。

在a网页中

document.getElementById("iframe").contentWindow.document

通过上面的代码可以获取b窗口的DOM。

在b窗口中

window

通过上面的代码可以获取a窗口的DOM。

注意:domain的使用必须在一级域名相同时,才能规避同源限制

window.name

window.name是浏览器窗口的一个属性,在一个窗口的生命周期里,不论是否同源,窗口里载入的所有页面都有权限对window.name进行读写。利用这一特性,我们可以实现在同一个窗口里,载入的不同网页之间的通信。

下面举个实例说明下如何使用window.name进行跨域:

原理:这里用到两个特性,

  • 在一个窗口下,先后载入的页面都可以对window.name进行读写
  • 同源或者一级域名相同并且domain相同的父子窗口可以相互获得DOM

首先,需要三个页面

  • http://a.ziv.com/a.html 获得数据、处理数据的页面
  • http://a.ziv.com/proxy.html 中间(代理)页面,一般是没有内容的html文件,必须与a页面一级域名相同,为了使a页面能够获得window.name这个属性
  • http://b.viz.com/data.html 拥有数据的页面

具体步骤如下:

  1. 在数据页面data.html中通过window.name,设置需要的数据。
    <script type="text/javascript">
    window.name = 'data!'; //需要传输的数据,浏览器一般支持2m的大小,这里数据
    //格式可以是json、xml、字符串等类型数据。
    </script>
  2. 在处理数据的页面a.html中创建一个iframe,设置其src为数据页面http://b.viz.com/data.html;然后在a.html中监听iframe的onload事件,在事件触发时将iframe的src指向代理页面http://a.ziv.com/proxy.html;这个时候就可以通过iframe的window.name获得数据了。
  3. 获得数据后要销毁iframe,即释放内存,也保证安全,免得被后续的页面拿到window.name信息。
    <script type="text/javascript">
    var state = 0,
    iframe = document.createElement('iframe'),
    loadfn = function() {
    if (state === 1) {
    var data = iframe.contentWindow.name; // 读取数据
    console.log(data); //'data!'
    //第三步的代码,销毁iframe,保证安全
    iframe.contentWindow.document.write('');
    iframe.contentWindow.close();
    document.body.removeChild(iframe);
    } else if (state === 0) {
    state = 1;
    // 设置iframe src为中间页面
    iframe.contentWindow.location = "http://a.ziv.com/proxy.html";
    }
    };
    iframe.src = 'http://b.viz.com/data.html';
    if (iframe.attachEvent) {
    iframe.attachEvent('onload', loadfn); //兼容ie7、ie8
    } else {
    iframe.onload = loadfn;
    }
    document.body.appendChild(iframe);
    </script>

关于window.name数据格式:

json格式

<script type="text/javascript">
        window.name='{"name":"ziv"}'; 
</script>

json格式应该是程序猿的写法

<html>
    <script type="text/javascript">
        window.name = document.getElementsByTagName("script")      [0].innerHTML.match(/temps*=([wW]*)/)[1];
        temp= {
            name:"ziv", 
            age:"24"
        }  
    </script> 
</html>

HTML/XML数据格式

<html>
    <body>
        <p id="data">  
            this is <strong>html/xml-style</strong> data  
        </p>  
    </body>  
    <script type="text/javascript"> 
        window.name = document.getElementById("data").innerHTML;  
    </script>
</html>

使用window.name的优缺点

优点

  • 安全
  • 比使用片段识别符快
  • 容量大,可以支持2M左右的数据量

缺点

  • 需要监听子窗口window.name属性变化,影响网页性能

window.postMessage

window.postMessage是HTML5的新特性。HTML5支持的跨文档通信API为window对象新增了一个postMessage方法,该方法支持跨窗口通信,不论是否同源。

postMessage使用语法

otherWindow

otherWindow:目标窗口的一个引用(指的是给哪个窗口发消息),比如比如iframe的contentWindow属性,window.open返回的窗口对象。

message:需要发送的数据,通过结构化克隆算法序列化。

targetOrigin:用来指定接收消息的窗口,值可以是字符串“*”或者一个url,“*”表示无限制,url表示接收消息的窗口必须与这个url同源。一般情况下,能确定targetOrigin就不要设置为“*”,免得导致数据泄露。

transfer(可选):一串和message同时传递的transferable对象。传递后,对象的所有权就转移给了消息接收方,发送方不在保留。

接下来我们举个例子具体说明一下,

a网页是 http://aaa.com,b网页是http://bbb.com,在a网页中通过iframe设置b网页为子窗口

<

那么,a、b窗口可以相互获得彼此的DOM。

在a网页中

bWindow 

通过上面的代码,a网页可以往b网页发送消息。

b网页往a网页发送消息如下:

window.parent.postMessage('hi~', 'http://aaa.com');

a、b窗口需要通过监听message事件得到彼此发送的消息。

window

message的事件对象有三个属性:

event

b窗口可以通过message事件对象的属性source来指定回复消息的url,a、b可以通过origin属性过滤不是给自己发送的消息。

window

片段识别符

片段识别符是url #号后面的部分,比如:

http://www.ziv.com/a.html#hello

#后面的hello就是片段识别符,也称为hash

片段识别符有几个特点:

  • 修改片段识别符,页面不会重新刷新
  • 父窗口可以改变子窗口的片段识别符
  • 子窗口可以改变父窗口的片段识别符
  • 通过hashchange事件可以监听片段识别符的变化

根据片段识别符的特点,我们可以完成父子窗口通信

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值