如何禁用 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. 点击微博里的外链:
B. 在打开外链页面中,可以获取到 window.opener
的值。由于跨域,这里获取到的窗体句柄是有限的。
C. 通过修改 window.opener.location
,篡改了来源页面。如果篡改的页面是一个伪造的微博主页,那么就可以愉快的钓鱼了
3. 如何禁用 window.opener
3.1 设置 rel 属性
示例:
1 |
< 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 值。示例:
1 |
var newWin = window.open( 'https://lzw.me' );
|
2 |
newWin.opener = null ;
|
当然也可以这样改写所有 a
标签的行为:
01 |
$(documnet).on( 'click' , 'a' , function (e) {
|
02 |
var href = $( this ).prop( 'href' ),
|
03 |
newWin;
|
04 |
05 |
// 非同源链接
|
06 |
if (/^http(s)/i.test(href) && !href.indexOf(location.hostname)) {
|
07 |
e.preventDefault();
|
08 |
newWin = window.open(href);
|
09 |
newWin.opener = null ;
|
10 |
}
|
11 |
}); |