“iframe沙箱”技术安全吗?

时间:2011-12-08 01:22:57

标签: javascript iframe constructor safari

更新:由于这是无人接听的,我正在稍微改变这个问题。以下链接在Dean的博客上的帖子的评论表明这种技术在Safari中不起作用。

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

这是一个更新的blog post。它曾经说过:

  

Sandboxed natives ...在各种浏览器中都受支持,包括...... Safari 2.0 +

...但后来说iframe技术“除了Safari之外的所有主流浏览器都支持”,并且他展示的后备涉及使用伪造的构造函数和__proto__做一些奇怪的事情,这看起来有点像hacky。 / p>

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

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


原帖

我知道之前已经问过这个问题,但我有一个特定的解决方案,我想知道这种解决方案之前是否已经讨论过,我想知道它是多么可靠和被广泛接受。

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

因此,我想到的解决方案是这样的:创建另一个窗口,在该窗口中为原生构造函数的原型添加功能,并在程序中使用这些构造函数。

此示例使用Array函数将My.Array扩展为each,将String扩展为My.String并使用alert函数。

    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

2 个答案:

答案 0 :(得分:6)

我在各种浏览器(Safari,Opera,IE7-9,Chrome,Firefox)中运行此页面并获得了一致的结果,除了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>

答案 1 :(得分:1)

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