一、概述
我们知道,网页里的a标签默认在当前窗口跳转链接地址,如果需要在新窗口打开,需要给 a 标签添加一个target="_blank"属性,这个属性的意思是在新的浏览器窗口打开此超链接,但是这个其实是有安全缺陷的,当我们在这样的写的时候一个非常简单的钓鱼攻击的漏洞就这样产生了。
二、原理
熟悉js的朋友都应该知道当我们在调用window下的open方法创建一个新窗口的同时,我们可以获得一个创建窗口的opener句柄,但你也许没注意到,通过target="_blank"点开的窗口活着标签页,子窗口也能捕获opener句柄,通过这个句柄,子窗口可以访问到父窗口的一些属性,虽然很有限,但是我们却可以修改父窗口的页面地址,让父窗口显示指定的页面。
举个例子,在页面a.html中有这样一段代码:
<a href="b.html" target="_blank">跳转</a>;
当我们点击页面a.html中的跳转链接时,浏览器会在新的窗口或标签页中打开b.html,假如这个时候b.html中有这样一段js代码:
if (window.opener) {
window.opener.location.href = 'b.html';
}
当页面b.html被打开的同时原来打开a.html的标签页会被重定向到b.html, b.html可以是和原来域完全不相关的其它域的资源。
三、性能
除了安全隐患外,还有可能造成性能问题。通过target="_blank"打开的新 窗口,跟原来的页面窗口共用一个进程。如果这个新页面执行了一大堆性能不好的 JavaScript 代码,占用了大量系统资源,那你原来的页面也会受到池鱼之殃。
四、防范
如果需要限制window.opener的访问行为,我们只需要在原始页面每个使用了 target="_blank" 的链接中加上一个 rel=“noopener” 属性。
但是,火狐并不支持这个属性值,火狐浏览器里需要写成 rel=“noreferrer” ,所以我们可以将两个属性值合并写成 rel=“noopener noreferrer” 来完整覆盖。
这样新窗口的window.openner就是null了,而且会让新窗口运行在独立的进程里,不会拖累原来页面的进程。
当然,我们也可以通过js来控制来限制句柄的访问,代码如下:
var otherWindow = window.open();
otherWindow.opener = null;
otherWindow.location = url;
otherWindow.target = "_blank";
五、总结
在开发中,我们以后在写a标签的时候尽量都在target="_blank"后面添加一句 rel=“noopener noreferrer”