检测JavaScript是否在沙盒Iframe中执行

Detect if JavaScript is Executing In a Sandboxed Iframe?

本文关键字:Iframe 执行 JavaScript 是否 检测      更新时间:2023-09-26

我有一个产品在Flash中播放视频(如果可用),如果Flash不可用,则返回HTML5。

我找不到一种方法来确定JavaScript是否在具有"沙盒"属性的Iframe中执行,这对我的解决方案来说是必要的,因为沙盒Iframe禁用了所有插件。沙盒iframe可以如此简单:

<iframe src="http://www.cross-domain.com/" sandbox="allow-scripts">

为了确定是否启用了Flash,我使用了swfobject的方法来检查navigator.plugins["Shockwave Flash"].description,即使在沙盒iframe中也会设置该方法。我可以加载swf对象,但它不能播放。

要复制此问题,请访问http://jsfiddle.net/max_winderbaum/9cqkjo45/,打开您的chrome检查器,然后单击"运行"。跨域站点上的脚本将在沙盒iframe的上下文中暂停。

根据W3规范http://dev.w3.org/html5/spec-preview/browsers.html#sandboxing-标志集,在JavaScript可以访问的文档上应该有一个"活动沙箱标志集"(至少我是这样阅读规范的)。iframe的文档上似乎没有设置任何标志。

有人对如何检测JavaScript是否在沙盒iframe中执行有任何想法/解决方案吗?

我会考虑不同类型的iframe(选择第一种适用的情况):

  • 带有沙盒脚本浏览上下文标志的Iframe

    也就是说,具有不包含allow-scripts关键字的sandbox属性的iframe。

    此标志阻止脚本执行。特别是,您不能使用脚本来检查iframe是否是沙盒的。

  • 没有沙盒源浏览上下文标志的同源iframe

    也就是说,不具有sandbox属性的同源iframe,或者具有包含allow-same-originallow-scripts关键字的sandbox属性的同源IFrame。

    在这种情况下,可以使用frameElement全局属性来访问框架元素(如果不在iframe中使用,则返回null)。

    一旦引用了iframe,就可以使用hasAttributegetAttribute来检查其sandboxed属性。还有sandboxed属性,它应该返回DOMSettableTokenList(旧的浏览器可能会根据旧的规范返回字符串)。

  • 没有沙盒源浏览上下文标志的跨源iframe

    也就是说,不具有sandbox属性的跨原点iframe,或者具有包含allow-same-originallow-scripts关键字的sandbox属性的跨原产地iframe。

    在这种情况下,frameElement的使用被阻止:

    • 根据W3C的说法,它应该抛出一个SecurityError异常。这是由Chrome实现的
    • 根据WHATWG,它应该返回null。这是由Firefox实现的

    那么,在这种情况下,我认为你无法区分iframe是否是沙盒的。但是,由于在跨源iframe中使用allow-same-origin没有多大用处,请考虑假设iframe没有沙盒。
  • 带有沙盒原始浏览上下文标志的Iframe

    也就是说,具有不包含allow-same-origin关键字但包含allow-scripts关键字的sandbox属性的iframe。

    与前面的情况一样,frameElement的使用被阻止。

    但是,您可以检测到这种情况,因为document.domain将是空字符串。

注意:Firefox将数据URI视为同源,所以没关系。然而,Chrome将它们视为跨源。则frameElement不起作用,并且无论iframe是否是沙盒的,document.domain都是空字符串。您可以检查location.protocol是否为'data:'字符串来检测数据URI。

通常,您可以尝试类似的方法

function isSandboxedIframe() {
  if (window.parent === window) return 'no-iframe';
  try { var f = window.frameElement; } catch(err) { f = null; }
  if(f === null) {
    if(document.domain !== '') return 'unkown'; // Probably 'non-sandboxed'
    if(location.protocol !== 'data:') return 'sandboxed';
    return 'unkown'; // Can be 'sandboxed' on Firefox
  }
  return f.hasAttribute('sandbox') ? 'sandboxed' : 'non-sandboxed';
}

项目喷砂器可以帮助您检测是否在沙盒中运行。

沙盒首先检查其自身是否已被框化,然后扫描框架元素的属性以检测有关其自身的一些信息。包括framedcrossOriginsandboxedsandboxAllowancesunsandboxableresandboxablesandboxable

在我们的例子中,为了检测它本身是否是沙盒的,它检查框架元素是否具有属性sandbox

// On below `frameEl` is the detected frame element
try {
  result.sandboxed = frameEl.hasAttribute("sandbox");
}
catch (sandboxErr) {
  result.sandboxed = null;
  if (typeof errback === "function") {
    errback(sandboxErr);
  }
}

我试图复制你的问题,并测试这个解决方案是否有效,由于安全问题,我不得不将脚本粘贴到窗口中。

<html>
    <head>
    </head>
    <body>
    <script>
        //Paste the contents of the script(https://raw.githubusercontent.com/JamesMGreene/sandblaster/master/dist/sandblaster.js) here
        var result = sandblaster.detect();
        if(result.sandboxed === true) {
            //sandboxed
        }
        debugger;
    </script>
    </body>
</html>

下面是一个演示:http://jsfiddle.net/Starx/tzmn4088/这表明了这一点。