Search code examples
iframegoogle-chrome-extensiongoogle-chrome-oskiosk-modechromebook

ChromeOS kiosk limitations: bypass framekiller


I'm developing a ChromeOS kiosk application (website + chrome extension) which suppose to run in Kiosk Mode on managed Chromebook devices. Application displays external web content which I don't own, I'm using sandboxed iframes to display that web content. These external websites should not escape their iframes, that's why I sandbox them. The app is basically a simple web browser but instead of tabs I use iframes, and the top frame (window.top) is the wrapper around these iframes. With all ChromeOS technical limitations I was able to bypass most of the iframe checks (x-frame-options, csp, blocked 302...) using the extension. However there is one I'm stuck with - framekillers. I can't properly display websites which do self !== top type of checks.

Is there a way to bypass it too somehow? I'm fine with refactoring my app completely or use something else instead of iframe. The app has to fulfil only one condition though - kiosk mode on a managed chromebook.

It's unfortunate that Chrome Apps with <webview> tag were deprecated and Android apps can't run in Kiosk mode anymore. This would solve all my issues easily by just using something else than iframes.

I've tried injecting the following buster <script> via a content script but it doesn't seem to work, websites seems to be doing something more advanced.

buster.ts

function buster() {
  if (top !== self) {
    (window.self as any) = window.top;
    (window.parent as any) = window.top;
  }
}
buster();

content-script.ts

const b = document.createElement('script');
b.src = chrome.runtime.getURL('buster.js');
const el = document.head || document.documentElement;
el.insertBefore(b, el.firstChild);
console.debug('buster is injected');

Solution

  • solution based on @wOxxOm comment (for MV3 extension):

    background.ts

    chrome.scripting.registerContentScripts([
      {
        allFrames: true,
        id: 'some-id',
        js: ['buster.js'],
        matches: ['<all_urls>'],
        runAt: 'document_start',
        world: 'MAIN',
      },
    ]);
    

    buster.ts

    function buster() {
      if (top !== self) {
        (window.self as any) = window.top;
      }
    }
    buster();