Безопасна ли техника "iframe sandbox"?
Обновление:. Поскольку это не отвечает, я немного меняю вопрос. Комментарии к сообщению на блоге Dean, указанном ниже, показывают, что этот метод не работает в Safari.
Теперь мой вопрос: работает ли описанная ниже техника * в современных браузерах и, в частности, кто-то может подтвердить, работает ли она в Safari?
Вот более поздний пост в блоге. В какой-то момент он говорит:
Песочницы-туземцы... поддерживаются в различных браузерах, в том числе... Safari 2.0 +
... но позже говорит, что метод iframe "поддерживается всеми главными браузерами, кроме Safari", и сделанный им резерв включает в себя выполнение некоторых странных вещей с фальшивыми конструкторами и __proto__
, которые кажутся немного взломанными.
Мне почти трудно поверить, что два разных окна могут фактически использовать один и тот же, скажем, Object.prototype. Что происходит с междоменными iframe? Если я модифицирую прототипы в одном кадре, измените ли прототипы в другом кадре? Это кажется очевидной проблемой безопасности. Кто-то, пожалуйста, пролил свет на эту ситуацию.
* Под "work" я подразумеваю My.Object != Object
, поэтому прототипы могут быть изменены в одном окне, не затрагивая другого.
Оригинальное сообщение
Я знаю, что это было задано раньше, но у меня есть конкретное решение, и я хочу знать, обсуждался ли этот тип решения раньше и где я могу узнать, насколько он надежный и хорошо принят.
Вопрос заключается в том, как распространять собственные типы в javascript без фактического использования самих типов, поэтому просто изменить Array.prototype не стоит (может быть, другой код используется для... в массивах). Создание поддельного конструктора, возвращающего собственный массив с некоторыми функциями, на которые наложено, не похоже на хорошее решение, фактически расширение внутренних объектов кажется лучше. Но вы также не можете использовать обычное расширение для шаблона-оболочки прототипа javascript-функции с родными типами, потому что вы получите ошибки, такие как "push 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 sandbox, чтобы не путать с атрибутом песочницы iframe HTML5.
связаны:
http://dean.edwards.name/weblog/2006/11/hooray/
http://webreflection.blogspot.com/2008/03/javascript-arrayobject.html
Ответы
Ответ 1
Я запустил эту страницу в разных браузерах (Safari, Opera, IE7-9, Chrome, Firefox) и получил согласованные результаты со всем, кроме firefox, в firefox прототипы изолированы, так что хороший, но второй тест по какой- Fire Fox. Прототип 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>
Ответ 2
Если у вас есть два разных фрейма с содержимым, загруженным из разных доменов, то ни один современный браузер не сможет взаимодействовать на уровне JavaScript между ними по очевидным соображениям безопасности. Лучше всего было бы настроить тест и посмотреть, что произойдет для себя, но я уверен, что то, что вы описываете, должно быть безопасным для большинства браузеров.