Обнаруживать, выполняется ли JavaScript в изолированном iframe?
У меня есть продукт, который воспроизводит видео во Flash (если доступно) и возвращается к HTML5, если Flash недоступен.
Я не могу найти способ определить, выполняется ли JavaScript в iframe с атрибутом "песочница", который необходим для моего решения, потому что изолированные iframes изолированы от всех плагинов. Песочница iframe может быть простой:
<iframe src="http://www.cross-domain.com/" sandbox="allow-scripts">
Чтобы определить, включена ли Flash, я использую swfobject метод проверки описания navigator.plugins [ "Shockwave Flash" ]., которое устанавливается даже в изолированном iframe. Я могу загрузить объект swf, но он не воспроизводится.
Чтобы воспроизвести эту проблему, зайдите в http://jsfiddle.net/max_winderbaum/9cqkjo45/, откройте свой хромовый инспектор и нажмите "Запустить". script на междоменном сайте приостановится в контексте изолированного iframe.
В соответствии со спецификацией W3 в http://dev.w3.org/html5/spec-preview/browsers.html#sandboxing-flag-set предполагается, что в документе, к которому может обращаться JavaScript, должен быть установлен "активный флаг песочницы" (по крайней мере, тот как я читаю спецификацию). В документе iframe не установлен какой-либо флаг.
Есть ли у кого-нибудь идеи/решения о том, как определить, выполняется ли JavaScript из изолированного iframe?
Ответы
Ответ 1
Проект sandblaster может помочь вам определить, работает ли вы в песочнице.
Песочница проверяет, сначала ли создан кадр, а затем просматривает атрибуты элемента фрейма для обнаружения нескольких сведений о себе. Они включают в себя framed
, crossOrigin
, sandboxed
, sandboxAllowances
, unsandboxable
, resandboxable
, sandboxable
.
Чтобы определить, является ли сам песочником в нашем случае, он проверяет, имеет ли элемент фрейма атрибут 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);
}
}
Я попытался реплицировать вашу проблему и проверить, работает ли это решение, мне пришлось вставить script в само окно из-за проблемы с безопасностью.
<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/, который показывает, что это работает.
Ответ 2
Я рассмотрю различные типы iframes (выберите первый применимый случай):
-
iframes с песочными сценариями просмотра контекстного флага
То есть, iframes с атрибутом sandbox
, который не содержит allow-scripts
.
Этот флаг блокирует script исполнение. В частности, вы не можете использовать script, чтобы проверить, изолирован ли iframe.
-
Фрагменты с одинаковым происхождением без флажок контекста просмотра в песочнице
То есть, с одинаковыми исходными фреймами без атрибута sandbox
или с одинаковыми исходными фреймами с sandbox
, который содержит allow-same-origin
и allow-scripts
.
В этом случае вы можете использовать глобальное свойство frameElement
для доступа к элементу фрейма (возвращает null
, когда он не используется внутри IFrame).
Как только у вас есть ссылка на iframe, вы можете использовать hasAttribute
или getAttribute
, чтобы проверить его sandboxed
. Существует также свойство sandboxed
, которое должно возвращать DOMSettableTokenList
(старые браузеры могут возвращать строку в соответствии со старой спецификацией).
-
Фрагменты с перекрестным происхождением без флажок контекста просмотра изолированных песочников
То есть, iframe с перекрестным началом без атрибута sandbox
или iframe с перекрестным началом с sandbox
, который содержит allow-same-origin
и allow-scripts
.
В этом случае использование frameElement
заблокировано:
Тогда я не думаю, что вы можете отличить, изолирован ли iframe или нет в этом случае. Однако, поскольку использование allow-same-origin
в перекрестном iframe не очень полезно, считайте, что iframe не изолирован.
-
Ифрагмы с флажок контекста просмотра изолированных песочниц
То есть, iframes с атрибутом sandbox
, который не содержит allow-same-origin
, но содержит ключевое слово allow-scripts
.
Как и в предыдущем случае, использование frameElement
заблокировано.
Однако вы можете обнаружить этот случай, потому что document.domain
будет пустой строкой.
Примечание: Firefox обрабатывает URI данных как одноименное, так что это нормально. Однако Chrome относится к ним как к перекрестному происхождению. Тогда frameElement
не работает, а document.domain
- это пустая строка, независимо от того, изолирована ли iframe или нет. Вы можете проверить, есть ли 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';
}