是“iframe沙盒”技术安全

Is the "iframe sandbox" technique safe?

本文关键字:技术 安全 沙盒 iframe      更新时间:2023-09-26

Update:由于这是没有答案的,我稍微改变了这个问题。下面链接的Dean博客上的评论指出,这种技术在Safari中不起作用。

我现在的问题是:下面描述的技术在现代浏览器中工作吗?特别是有人能确认它是否在Safari中工作吗?

这是最近的一篇博客文章。它在某处说:

沙盒原生体…在各种浏览器中都支持,包括…Safari 2.0 +

…但后来说iframe技术"被所有主流浏览器支持,除了Safari",他展示的退路包括用伪造的构造函数和__proto__做一些奇怪的事情,看起来有点黑客。

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

*这里的"工作"指的是My.Object != Object,所以原型可以在一个窗口修改而不影响另一个窗口。


原始文章

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

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

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

本例扩展ArrayMy.Array,扩展each函数,扩展StringMy.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

我在各种浏览器(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>

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