【问题标题】:Is the "iframe sandbox" technique safe?“iframe 沙盒”技术安全吗?
【发布时间】:2011-12-08 01:22:56
【问题描述】:

更新:由于这个问题没有答案,我稍微改变一下这个问题。对下面链接的 Dean 博客上的帖子的评论表明,这种技术在 Safari 中不起作用。

我现在的问题是:下面描述的技术在现代浏览器中是否有效*,尤其是有人可以确认它在 Safari 中是否有效吗?

这是更新的blog post。它在某一时刻说:

Sandboxed natives ... 支持多种浏览器,包括 ... Safari 2.0+

...但后来表示 iframe 技术“被所有主流浏览器支持,除了 Safari”,他展示的后备方案涉及使用伪造的构造函数和 __proto__ 做一些奇怪的事情,这似乎有点 hacky。

我几乎很难相信两个不同的窗口实际上可以共享同一个,比如 Object.prototype。跨域 iframe 会发生什么?如果我修改一帧中的原型,是否修改另一帧中的原型?这似乎是一个明显的安全问题。有人请阐明这种情况。

* “工作”是指My.Object != Object,因此可以在一个窗口中修改原型而不影响另一个窗口。


原帖

我知道以前有人问过这个问题,但我有一个具体的解决方案,我想知道以前是否讨论过这种类型的解决方案,以及我可以从哪里了解到它的可靠性和被广泛接受的程度。

问题是如何在 javascript 中扩展原生类型,而不会真正弄乱类型本身,所以仅仅改变 Array.prototype 是不好的(也许其他代码正在使用 for..in 和数组)。创建一个返回带有一些附加功能的本机数组的假构造函数似乎也不是一个好的解决方案,实际上扩展本机对象似乎更好。但是你也不能用原生类型做普通的 javascript 虚拟函数原型 switcharoo 样式扩展,因为当你尝试调用原生函数时,你会得到像“push is not generic”这样的错误。

所以,我想到的解决方案是这样工作的:创建另一个窗口,在该窗口中向本机构造函数的原型添加功能,然后在程序中使用这些构造函数。

此示例将Array 扩展为具有each 函数的My.Array,并将String 扩展为具有My.StringMy.String 函数。

    var My = (function(){

      // create an iframe to get a separate global scope
      var iframe = document.createElement('iframe');
      iframe.style.height = '0px';
      iframe.style.width = '0px';
      iframe.style.border = 'none';
      iframe.style.position = 'absolute';
      iframe.style.left = '-99999px';
      document.documentElement.appendChild(iframe);
      var My = iframe.contentWindow;

      My.String.prototype.alert = function(){
        alert(this);
      }

      My.Array.prototype.each = function(callback){
        for (var i=0, l=this.length; i<l; i++) {
          callback(this[i], i);
        }
      }

      return My;

    }());

再次,我的问题是这种方法之前是否已经讨论过,它叫什么,我可以在哪里找到更多信息等。我想知道是否有一种更简洁的方法可以在不使用 iframe 的情况下获得另一个全局范围,或者如果在某些 javascript 引擎中由于某种原因这可能会失败,或者如果有人认为这是一个特别糟糕的主意或其他什么。


更新:我猜人们将这种东西称为 iframe 沙箱,不要与 HTML5 iframe 沙箱属性混淆。

相关:

http://dean.edwards.name/weblog/2006/11/hooray/

http://webreflection.blogspot.com/2008/03/javascript-arrayobject.html

【问题讨论】:

  • 获得一个干净的窗口对象是对 iframe 的合法使用,尽管这种技术最常用于摆脱那些额外的方法,然后添加它们......跨度>
  • missingno,您知道目前使用这种技术的任何事情吗?它有很多奇怪的后果,我想如果它被使用的话,一定会有一些关于它的邮件列表讨论
  • 我记得读过一个来自 Disqus 的人的presentation。他们使用这种技巧是因为他们需要能够将代码嵌入到任何地方。
  • 谢谢,很好的介绍。扩展本机类型的好处是它很有用,但很烦人。这种技术对于命名空间扩展的东西似乎和它在当前窗口中处理扩展的东西一样好。不过,iframe hack 很丑陋。 typeof 也始终是 object,而 My.Array 不是 instanceof Array。
  • 如果你只是想在你的函数中使用this,你可以使用callapply

标签: javascript iframe constructor safari


【解决方案1】:

我在各种浏览器(Safari、Opera、IE7-9、Chrome、Firefox)中运行了这个页面,除了 firefox 之外的所有东西都得到了一致的结果,在 firefox 中,原型是沙盒的,所以这很好,但第二次测试由于某种原因失败了火狐。 iframe 原型不会立即增强。但是,如果您不打算增强它,这并不重要。您可以尝试在更多浏览器中运行它进行测试。

请注意,这并没有真正测试任何怪癖,例如(My.Array().slice 将根据浏览器返回主要的window 数组......)并且可能还有更多。所以我会说这很不安全。

不管怎样,这太过分了,而且似乎工作太多而没有真正的收获。

<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
(function(){
    var ifr = document.createElement("iframe"),
        callbacks = [],
        hasReadyState = "readyState" in ifr;

    ifr.style.display = "none";


    document.body.appendChild(ifr);
    ifrDoc = ifr.contentWindow.document;
    ifrDoc.open();
    ifrDoc.write( "<!DOCTYPE html><html><head></head><body>"+"<"+"script"+">var w = this;"+"</"+"script"+">"+"</body></html>");
    ifrDoc.close();

    if( hasReadyState ) {

        ifr.onreadystatechange = function(){
            if( this.readyState === "complete" ) {
                fireCallbacks();
            }
        };

    }

    function fireCallbacks(){
        var i, l = callbacks.length;
        window.My = ifr.contentWindow.w;

        for( i = 0; i < l; ++i ) {
            callbacks[i]();
        }

        callbacks.length = 0;


    }

    function checkReady(){

        if( hasReadyState && ifr.readyState === "complete" ) {
        fireCallbacks();
        }
        else if( !hasReadyState ) {
        fireCallbacks();
        }
    }

    window.MyReady = function(fn){
        if( typeof fn == "function" ) {
            callbacks.push( fn );
        }
    };


window.onload = checkReady; //Change this to DOMReady or whatever
})()


MyReady( function(){

    My.Object.prototype.test = "hi";

    var a = new My.Object(),
        b = new Object();

    console.log( Math.random(), My.Object !== Object && b.test !== "hi", a.test === "hi" );

});
</script>

</body>
</html>

【讨论】:

  • 标记为正确。毕竟,出于各种原因,我决定不做 iframe 沙盒。
【解决方案2】:

如果您有两个不同的框架,它们的内容从不同的域加载,那么出于明显的安全原因,现代浏览器将不允许它们之间在 JavaScript 级别上进行任何交互。你最好的选择当然是设置一个测试,看看你自己会发生什么,但我很确定你所描述的内容在大多数浏览器上应该是安全的。

【讨论】:

  • 是的,但我没有 mac。真的,我只需要有人为我测试它。另外我想知道你是否可以通过在不同的子域启动 iframe 然后更改 document.domain 来伪造它。
  • 啊,好吧,是的,我也没有 Mac。我会说在 IE、FireFox 和 Chrome 中尝试一下。如果这三个都通过了,我会说你很高兴。以后你总可以找人在 Safari 中测试它,但我认为它不应该成为你的优先级。当然,如果你真的想要,你总是可以在 VirtualBox 中设置一个 MacOS 实例......
猜你喜欢
  • 1970-01-01
  • 2014-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-22
  • 2014-03-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多