iframe 禁止打开新窗口_打开新窗口的安全和性能问题

相信大部分同学都接到过"点击页面某个地方从新窗口打开一个页面"的需求, 一般这个需求都有一下两种处理方式来完成:

        1. a标签加上target="_blank"属性

        2. window.open(url)

但是以上两种处理方式可能会遇到已下问题:

        1. 用户账户或个人信息被盗取

        2. 打开新页面后, 原窗口页面出现卡顿情况

经过一顿猛操作去验证, 发现新窗口打开新页面可能出现安全问题和性能问题, 原因是Window对象的opener属性

(关于window opener属性解释摘自菜鸟教程)

5107dc98a5e4a679124c9baa9842c5da.png

废话不多说, 我们通过代码来检验

<html><head>  <meta charset="utf-8">  <title>原始页面title>head><body><h1 style="color: red;" id="alert-tips">h1><a href="./target.html" target="_blank">1.target _blanka><br><a id="btn-diff" href="javascript:void(0);">2.window.opena><br><a id="btn-open" href="javascript:void(0);">3.window.open并且设置opener为nulla><br><a id="btn-iframe" href="javascript:void(0);">4.新建iframe打开a><br><a href="./target.html" target="_blank" rel="noopener">5.target _blank noopenera><p id="random-number">0.6890402854817066p><script>  window.onload = function () {    var randomItem = document.getElementById('random-number'),      btnDiff = document.getElementById('btn-diff'),      btnIframe = document.getElementById('btn-iframe'),      btnOpen = document.getElementById('btn-open');    console.log('DOM READY');    btnDiff.addEventListener('click', function () {      window.open('./target.html');    });    btnIframe.addEventListener('click', function () {      iframeOpen('./target.html');    });    btnOpen.addEventListener('click', function () {      var child = window.open('./target.html');      child.opener = null;    })    var setRandom = function () {      randomItem.innerHTML = Math.random();      setTimeout(setRandom, 10);    }    checkHash();    setRandom();  }  window.onhashchange = checkHash;  function checkHash() {    if (location.hash.indexOf('#hack') >= 0) {      document.getElementById('alert-tips').innerHTML = '你被HACK了啊!这个页面的地址已经变了!';    }  }  /**   * Opens the provided url by injecting a hidden iframe that calls   * window.open(), then removes the iframe from the DOM.   *   * @param   {string} url The url to open   * @param   {string} [strWindowName]   * @param   {string} [strWindowFeatures]   * @returns {Window}   */  function iframeOpen(url, strWindowName, strWindowFeatures) {    var iframe, iframeDoc, script, openArgs, newWin;    iframe = document.createElement('iframe');    iframe.style.display = 'none';    document.body.appendChild(iframe);    iframeDoc = iframe.contentDocument || iframe.contentWindow.document;    openArgs = '"' + url + '"';    if (strWindowName) {      openArgs += ', "' + strWindowName + '"';    }    if (strWindowFeatures) {      openArgs += ', "' + strWindowFeatures + '"';    }    script = iframeDoc.createElement('script');    script.type = 'text/javascript';    script.text = 'window.parent = null; window.top = null;' +      'window.frameElement = null; var child = window.open(' + openArgs + ');' +      'child.opener = null';    iframeDoc.body.appendChild(script);    newWin = iframe.contentWindow.child;    document.body.removeChild(iframe);    return newWin;  }script>body>html>

(如上为origin.html)

<html><head>  <meta charset="utf-8">  <title>目标页面title>head><body><p id="content">p><script>  window.onload = function(arguments) {    hackOrigin();    superFunJankTime();  };  function hackOrigin() {    var content = document.getElementById('content');    if (window.opener) {      // console.log('window.opener', window.opener)      // console.log('opener', opener)      opener.location = './origin.html#hack';      content.innerHTML = 'HACK成功,再看看上个TAB?';    } else {      content.innerHTML = 'HACK失败。。。。';    }  }  function superFunJankTime() {    var start = Date.now();    while (Date.now() - start < 1000);    setTimeout(superFunJankTime, 1000);  }script>body>html>

(如上为target.html)

经过动手尝试后, 发现原来第1,2个跳转链接是可以通过window.opener.location=newUrl来重写原页面的url的, 即使与原窗口的页面不同域; 利用这种方式原始页面窗口的链接就被悄悄换成钓鱼页面的地址. 一般人也不会关注到url悄悄变了, 因此就会造成安全性问题.

那么, 透过上面的代码, 不难发现, 这个安全性问题可以通过3,4,5可以解决安全性问题; 但是, 如果透过3,4去发生跳转的话, 我们会发现一开始的页面上的一串鬼畜随机数, 偶尔有点小卡顿; 这个随机数是通过一个定时器生成的, 每隔一段时间就有一个持续循环. 这个循环在阻塞新页面本身的js线程的同时, 也阻止了opener(即打开了新页面的原始页面)里的js线程. 若这种类似的操作很多的话, 原始页面的可能会卡死;

问题来了, 为啥新窗口会影响原来窗口的线程呢? chrome不是每个标签页一个单独的进程吗? 进程内包含若干线程吗?

chrome确实有不同的标签页面使用不同的进程和线程, 但是有个例外, 通过a标签的target="_blank"属性, 或者window.open(url)在新窗口中打开页面, 会与原窗口共用进程和线程. 这是因为opener中含有DOM信息, 两个进程中同时hold住这个DOM信息, 在多个进程下很难控制, 于是放到一个进程里面

当然, 上述的问题也有对应的解决方案: 通过a标签上添加noopener属性, 可将新打开窗口的opener置为空. 这个方案可解决除IE以外的安全问题和所有现代浏览器的性能问题

总结一下:

1. 使a标签noopener属性, 将新打开的窗口opener置为空(推荐)

    特点: 可解决除IE外的安全问题和所有现代浏览器的性能问题

2. window.open并设置opener为空

    特点: 可解决所有除safari下的安全问题, 无法解决性能问题

var newWindow = window.open();newWindow.opener = null;newWindow.location = 'url';newWindow.target = '_blank';

3. 新建iframe中打开新窗口, 然后关掉iframe

    特点: 可解决safari下的安全问题, 无法解决性能问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值