“iframe sandbox”技术安全吗?

17

更新:由于该问题尚未得到解答,我稍作修改。以下链接Dean博客文章的评论表明这种技术在Safari中不起作用。

我的问题是:描述的技术在现代浏览器中是否可行*,特别地,有人能证实它在Safari中是否可行吗?

这里有一篇更近期的博客文章。其中提到:

沙箱本机……受到多种浏览器的支持,包括……Safari 2.0+

但后来又说,iframe技术“被除Safari以外的所有主流浏览器支持”,并且他展示的备选方案涉及使用伪造的构造函数和__proto__进行一些奇怪的操作,看起来有点hacky。

我几乎难以相信两个不同的窗口实际上可以共享同一个对象原型,比如Object.prototype。跨域iframe会发生什么情况?如果我在一个框架中修改了原型,另一个框架中的原型是否也会被修改?这似乎是一个显而易见的安全问题。请有人解释一下这种情况。

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


原始帖子

我知道以前已经问过了,但我有一个特定的解决方案,并且我想知道是否以前讨论过这种类型的解决方案,以及我在哪里可以学习它的可靠性和广泛接受程度。

问题是如何扩展javascript中的本机类型,而不实际干扰类型本身,因此仅改变Array.prototype是不好的(可能其他代码正在使用for..in与数组)。创建一个返回带有一些函数的本机数组的伪构造函数似乎也不是一个好的解决方案,实际扩展本机对象似乎更好。但是,您也无法像使用常规javascript虚拟函数原型切换样式扩展本机类型,因为当您尝试调用本机函数时会出现错误,如“push不是通用的”。

因此,我所考虑的解决方案是:创建另一个窗口,在该窗口的本机构造函数的原型中添加功能,并在程序中使用这些构造函数。

此示例将Array扩展为带有each函数的My.Array以及将String扩展为带有alert函数的My.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引擎中可能因为某些原因而失败,或者是否有人认为这是一个特别糟糕的想法。


更新:我想人们称这种方法为< b > iframe沙盒 ,不要与HTML5 iframe沙盒属性混淆。

相关:

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

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


获取一个干净的 window 对象是 iframe 的合法用途,尽管这种技术最常用于去除那些额外的方法,而不是添加它们... - hugomg
missingno,你知道当前是否有东西在使用这种技术吗?它有一堆奇怪的影响力,我想如果有人在使用它的话,肯定会在某个邮件列表讨论中提到它。 - Dagg Nabbit
3
我记得阅读过一个来自Disqus的人的演示文稿。他们使用这种技巧,因为他们需要能够在基本上任何地方嵌入他们的代码。 - hugomg
谢谢,演示很不错。扩展本地类型的问题是它很有用,但很烦人。这种技术似乎对于为扩展的内容命名空间和在当前窗口中解决扩展的内容一样好。虽然 iframe hack 很丑陋。此外 typeof 总是对象,而 My.Array 不是 Array 的一个实例。 - Dagg Nabbit
如果你只是想在函数中使用 this,你可以使用 callapply - zzzzBov
2个回答

6
我在各种浏览器(Safari、Opera、IE7-9、Chrome、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>

1
标记为正确。出于各种原因,我决定不再进行iframe沙盒处理。 - Dagg Nabbit

1
如果您有两个不同的框架,其中包含从不同域加载的内容,则出于明显的安全原因,现代浏览器将不允许它们之间在JavaScript级别上进行任何交互。当然,您最好设置一个测试并自行查看发生了什么,但我相信您所描述的情况在大多数浏览器上应该是安全的。

是的,但我没有Mac。实际上,我只需要有人为我测试一下。另外,我想知道是否可以通过在不同的子域名上启动iframe,然后在之后更改document.domain来欺骗它。 - Dagg Nabbit
啊,好的,我也没有Mac。我建议你在IE、FireFox和Chrome中尝试一下。如果在这三个浏览器中都能通过测试,那么就可以放心使用了。你随时可以找人在Safari中测试,但我认为这不应该是你的优先考虑因素。当然,如果你真的想的话,你也可以在VirtualBox中设置一个MacOS实例... - Kris Craig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接