对钓鱼攻击者SAY NO——修复 target="_blank" 安全缺陷

by LauCyun Apr 04,2018 10:52:19 19,767 views

早在2014年,就已经有很多安全研究专家表示,target="_blank" 属性是非常不安全的一个属性,它将会为钓鱼攻击者带来了可乘之机。在2016年,@ALEX的一篇安全报告《Target="_blank" - the most underestimated vulnerability ever》详细介绍了。

最近,随着本博客的用户量增长,为了不让广大的用不户暴露在钓鱼攻击的风险之下,特此修复该漏洞。本文详细介绍其修复过程。

0x01 漏洞实现机制

当用户点击了某个网站中带有 target="_blank" 属性的超链接后,浏览器会单独新建一个标签页来显示该链接所指向的内容。但是请注意,在这一瞬间,浏览器会允许新建的标签页通过一个名为 window.opener 的浏览器API来与之前的网页进行短暂通信。

此时,攻击者就可以将恶意代码嵌入在新打开的网站中,然后检测用户是从哪一个网站跳转过来的,最后再利用 window.opener 接口来迫使原始网页打开一个新的URL地址。

比如说,如果用户点击了 Facebook 网站中一个带有 target="_blank" 属性的链接,那么攻击者就可以利用一个伪造的 Facebook 页面来替换原始的 Facebook 网页,然后要求用户重新输入用户名和密码。这样一来,攻击者便成功获取到了目标用户的凭证数据。

下图演示了攻击的实现过程和效果:


图1 攻击过程和效果(来源:softpedia

0x02 防御

iframe 中有 sandbox 属性,而链接,则可以使用下面的办法:

1. Referrer Policy 和 noreferrer

上面的攻击步骤中,用到了 HTTP Header 中的 Referer 属性,实际上可以在 HTTP 的响应头中增加 ReferrerPolicy 头来保证来源隐私安全。

ReferrerPolicy 需要修改后端代码来实现,而在前端,也可以使用 a 标签的 rel 属性来指定 rel="noreferrer" 来保证来源隐私安全。

<a href="https://laucyun.com" target="_blank" rel="noreferrer">LauCyun's Blog</a>

但是要注意的是:即使限制了 referer 的传递,仍然不能阻止原标签被恶意跳转。

2. noopener

为了安全,现代浏览器都支持在 a 标签的 rel 属性中指定 rel="noopener",这样,在打开的新标签页中,将无法再使用 opener 对象了,它为设置为了 null

<a href="https://laucyun.com" target="_blank" rel="noopener">LauCyun's Blog</a>

3. JavaScript

noopener 属性看似是解决了所有问题,但是...浏览器的兼容性问题...

可以看到,现在绝大多数浏览器都已经兼容了 rel="noopener" 属性了。但是,为了保护稍旧的“近代”浏览器或是很旧的“古代”浏览器甚至是“远古”浏览器,只有 noopener 属性还是远远不够的。

这时,就只能请出下面这段原生 JavaScript 来帮忙了。

"use strict";
function openUrl(url) {
    var newTab = window.open();
    newTab.opener = null;
    newTab.location = url;
}

0x03 修复推荐

首先,在网站中的链接上,如果使用了 target="_blank",就要带上 rel="noopener",并且建议带上 rel="noreferrer"。类似于这样:

<a href="https://laucyun.com" target="_blank" rel="noopener noreferrer">LauCyun's Blog</a>

当然,在跳转到第三方网站的时候,为了 SEO 权重,还建议带上 rel="nofollow",所以最终类似于这样:

<a href="https://laucyun.com" target="_blank" rel="noopener noreferrer nofollow">LauCyun's Blog</a>

0x04 性能

如果网站使用了 target="_blank",那么新打开的标签页的性能将会影响到当前页面。此时如果新打开的页面中执行了一个非常庞大的 JavaScript 脚本,那么原始标签页也会受到影响,会出现卡顿的现象(当然不至于卡死)。

而如果在链接中加入了 noopener,则此时两个标签页将会互不干扰,使得原页面的性能不会受到新页面的影响。

0x05 修复 CKEditor

由于本博客使用的编辑器是 CKEditor,而官方并没有修复该漏洞。下面以 link 插件为例:

首先,修改 ckeditor/plugins/link/dialogs/link.js 文件,修改如图2所示:


图2 link.js

其 ckeditor/plugins/link/dialogs/link.js 需修改两处:

  • 在 CKEDITOR.dialog.addcontents > id: 'target'elements > commit 中添加如下内容:
    if(a.target.type == '_blank'){a.rel="noopener noreferrer";}
  • 在 CKEDITOR.dialog.add > onOk 中添加如下内容:
    if(!a.rel){d.removeAttribute('rel');}

然后,修改 ckeditor/ckeditor.js 文件,修改如图3所示:


图3 ckeditor.js

其 ckeditor/ckeditor.js 只需修改一处:

  • CKEDITOR.plugins.link > getLinkAttributes 中添加如下内容:
    if (b.rel) {f['rel'] = b.rel;}

到此为此,就把 CKEditor 的 link 插件就修复完成了。

至于其他的插件同理,在这就不一一说明了。

0x06 声明

文中0x02、0x03、0x04三节引用《危险的 target="_blank" 与 “opener”》中的“防御”、“推荐”和“性能”的内容。

0x07 参考

Tags