禁用 window.opener

目录
[隐藏]

1. 什么是 window.opener

window.opener 表示打开当前窗体页面的的父窗体是谁。

例如,在 A 页面中,通过一个带有 target="_blank"a 标签打开了一个新的页面 B,那么在 B 页面里,window.opener 的值为 A 页面的 window 对象。

无来源的打开的页面,或者被禁止了 opener 的页面创建/打开,opener 的值为 null

2. window.opener 的安全问题

一般来说,打开同源(域名相同)的页面,不会有什么问题。但对于跨域的外部链接来说,存在一个被钓鱼的风险。
在跨域的情况下,window.opener 拿不到来源页面的具体内容,但是 window.opener.location 却是例外。它会带来什么问题呢?

举个栗子:

假如你在新浪微博首页设置了个人主页链接(例如: https://lzw.me),通过访问你的微博首页点击了这个链接,正常情况下会打开一个新页面,新页面自然是 https://lzw.me(志文工作室的首页)。

如果微博没有对这个主页链接设置禁用 window.opener 的跟踪,在打开的 https://lzw.me 页面,可以通过 window.opener.location 改写来源站点的地址。利用这一点,将来源站点改写到钓鱼站点页面上,例如跳转到伪造的微博登陆页面,这个时候是很难被用户发现的,那么你的账号就存在被钓鱼走的可能了。

下面以新浪微博作为演示。

A. 点击微博里的外链:

opener1

B. 在打开外链页面中,可以获取到 window.opener 的值。由于跨域,这里获取到的窗体句柄是有限的。

opener2

C. 通过修改 window.opener.location ,篡改了来源页面。如果篡改的页面是一个伪造的微博主页,那么就可以愉快的钓鱼了

opener3

3. 如何禁用 window.opener

3.1 设置 rel 属性

示例:

<a href="https://lzw.me" target="_blank" rel="noopener" rel="noreferrer">志文工作室</a>

rel=noopener 规定禁止新页面传递 rel=noopener,通过设置了此属性的链接打开的页面,其 window.opener 的值为 null。
但该属性在 chrome 49+,Opera 36+ 版本中才得到支持。

在不支持 rel=noopener 属性的浏览器中,可以使用 rel=noreferrer 禁用 HTTP 头部的 Referer 属性跟踪来源页面,得到的效果一样。

3.2 widow.open 方式

对于使用 widow.open 脚本打开的新页面,由于可以得到新页面的窗体句柄,那么可以改写它的 opener 值。示例:

var newWin = window.open('https://lzw.me');
newWin.opener = null;

当然也可以这样改写所有 a 标签的行为:

$(documnet).on('click', 'a', function(e) {
    var href = $(this).prop('href'),
        newWin;

    // 非同源链接
    if (/^http(s)/i.test(href) && !href.indexOf(location.hostname)) {
        e.preventDefault();
        newWin = window.open(href);
        newWin.opener = null;
    }
});
0 个评论
写个评论