Приложение Chrome: доступ к изолированному iframe из родительского окна

Я использую Knockoutjs в своем приложении Google Chrome. Чтобы иметь возможность использовать нокаут, я должен определить настоящий application.html как страницу песочницы и включить его как iframe в фиктивный контейнер. Структура приложения следующая:

- container.html
|
+-- application.html as iframe 
   |
   +-knockout and application.js

Iframe определяется следующим образом:

  <iframe src="application.html" frameborder="0"  
            sandbox="allow-same-origin allow-scripts" ></iframe>

Бег

document.getElementsByTagName("iframe")[0]

в инструменте проверки на container.html выдает следующую ошибку.

Sandbox access violation: Blocked a frame at "chrome-extension://hllbklabnppjkmnngfanldbllljfeaia" 
from accessing a frame at "chrome-extension://hllbklabnppjkmnngfanldbllljfeaia".  
The frame being accessed is sandboxed and lacks the "allow-same-origin" flag.

Как я могу получить доступ к документу iframe из его родителя?


person altunyurt    schedule 30.04.2013    source источник


Ответы (2)


Сделайте что-то вроде этого:

manifest.json

  "sandbox": {
    "pages": ["my_ui.html"]
  }

my_ui.html

  <script type="text/javascript" src="knockout-1.2.3.4.js"></script>
  <script type="text/javascript" src="my_ui.js"></script>

my_ui.js

this.onSomethingChange = function() {
  window.top.postMessage(
    { command: 'please-do-something', myArgument: this.myArgument() }, '*');
};

container.html

  <script type="text/javascript" src="container.js"></script>
  <iframe id="knockoutFrame" src="my_ui.html"></iframe>

контейнер.js

  window.addEventListener('message', function(event) {
    var kocw = document.getElementById('knockoutFrame').contentWindow;
    var anotherContentWindow = // etc.
    var dest;

    if (event.source == kocw) {
      // The knockout iframe sent us a message. So we'll forward it to our
      // app code.
      dest = anotherContentWindow;
    }
    if (event.source == anotherContentWindow) {
      // Our app code is responding to the knockout message (or initiating
      // a conversation with that iframe). Forward it to the knockout code.
      dest = kocw;
    }
    if (dest == null) {
      console.log('huh?');
    }

    // This makes container.js like a gatekeeper, bouncing valid messages between
    // the sandboxed page and the other page in your app. You should do
    // better validation here, making sure the command is real, the source
    // is as expected for the kind of command, etc.
    dest.postMessage(event.data, '*');
  }

Ваше утверждение «Я должен определить настоящий application.html как страницу песочницы и включить его как iframe в фиктивный контейнер», вероятно, не то, что вы хотели. Идея состоит в том, чтобы поместить в песочницу наименьшую возможную вещь, отправить сообщение на страницу привратника, которая проверяет сообщения, и заставить привратник пересылать узкие сообщения в логику вашего приложения, не изолированного в песочнице. Если вы просто запихнете все в песочницу, вы лишитесь цели песочницы.

Отказ от ответственности: я не исследовал этот код с точки зрения безопасности. Вы захотите предположить, что враждебные сообщения исходят из песочницы (или откуда-то еще, если уж на то пошло), и сделать все возможное для устранения этой угрозы.

person sowbug    schedule 30.04.2013
comment
Спасибо за ваш ответ. Я делаю почти то же самое. Все мое приложение нуждается в нокауте и доступе к некоторым другим API, недоступным для расширений. Я использую прокси-сервер, очень похожий на ваш, для передачи сообщений между iframe приложения и фоновой страницей. document.getElementById('knockoutFrame').contentWindow — это место, где я получаю ошибку нарушения доступа к песочнице в прокси-коде. - person altunyurt; 01.05.2013

Выяснили виновника. Это мой proxy.js, который включен в container.html и используется в качестве моста для передачи сообщений между приложением iframe и background.js. Следующая часть — это та, которая прослушивает сообщения, исходящие из iframe.

window.addEventListener("message",
    function(evt){
        console.log(evt); <= this is the problem
        var iframe = document.getElementById("application").contentWindow; <= not this one
        if (evt.source == iframe) {
            return chrome.runtime.sendMessage(null, evt.data);
        }
    }
);

Я не думал, что console.log будет причиной проблемы. Вместо этого я подозревал из строки document.getElem... Потому что попытка запустить этот код в окне проверки приложения вызывала ту же ошибку.

Но кажется, что console.log (консоль, похоже, принадлежит области container.html) обращается к некоторым внутренним элементам объекта события, которые не предназначены для доступа за пределами области действия iframe (что объясняет, почему я получаю ту же ошибку в консоли проверки). Удаление строки console.log решило эту проблему для меня.

person altunyurt    schedule 01.05.2013