Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript errors (localstorage, cookie) loading sandboxed iframe within Chrome Extension

I'm writing a Chrome Extension that shows a preview of a website of a user's choosing in a sandboxed iframe. I'm finding that a lot of pages do not render properly in the iframe because they get JavaScript errors such which breaks scripts that are important to rendering the page (like hiding a loading dialog):

"Uncaught DOMException: Failed to read the 'localStorage' property from 'Window':
The document is sandboxed and lacks the 'allow-same-origin' flag."

"Uncaught DOMException: Failed to read the 'cookie' property from 'Document':
The document is sandboxed and lacks the 'allow-same-origin' flag."

How can I safely sidestep these errors so that most pages will render as intended? They don't need to actually be able to save data to local storage or cookies, just render correctly. I've confirmed the same error happens if you put a sandboxed iframe on a regular website so it's not a Chrome Extension issue but I might be able to side step it because it's within a Chrome Extension.

Some notes:

  • My understanding is enabling the 'allow-same-origin' flag would be a huge security risk as it would give the iframe access to the context of the Chrome extension so I don't want to do that. Enabling this flag does fix the issue though. (Edit: I think this might actually be safe now. Is this true given my context?)

  • In Chrome settings you can block localstorage and cookies which can cause similar errors elsewhere. These settings have no impact here.

  • I tried loading my target page with an iframe inside another iframe inside my Chrome Extension page and got the same errors.

  • Is it possible to inject JavaScript into the iframe that would implement dummy versions of 'localStorage' and 'cookie'? I looked into content scripts but couldn't find a way to alter these global objects before the page's scripts ran. Is it possible?

My manifest file is like this:

    {
      "name": "test",
      "version": "0.0.1",
      "manifest_version": 2,
      "description": "",
      "icons": {
        "128": "assets/app-icon/app-icon-128x128.png"
      },
      "default_locale": "en",
      "background": {
        "scripts": [
          "scripts/background.js"
        ]
      },
      "permissions": [
        "clipboardWrite",
        "tabs",
        "storage",
        "webRequest",
        "webRequestBlocking",
        "unlimitedStorage",
        "<all_urls>"
      ],
      "browser_action": {
        "default_icon": {
          "128": "assets/app-icon/app-icon-128x128.png"
        }
      },
      "content_security_policy": "script-src 'self'; object-src 'self'"
    }

My background.js file is this:

  chrome.browserAction.onClicked.addListener(function(tab) {
    var url = chrome.extension.getURL('app.html');
    chrome.tabs.create({url: url});
  });

My app.html file is this:

   <html><body>
   <iframe src="https://codepen.io/TrentWalton/pen/eyaDr" sandbox="allow-scripts"></iframe>
    </body></html>

The bottom part of the codepen URL will render a page in a regular tab but in the iframe it'll be blank because of the errors mentioned at the start of the post.

like image 940
fstr Avatar asked Dec 09 '16 18:12

fstr


1 Answers

Using allow-same-origin is fine. It does not give the content access to the Chrome extension context. It does not grant anything beyond letting the iframe retain its original origin.

You have become concerned because of the name used for this permission. In my opinion, the name of this token is inappropriate. The name allow-same-origin implies that it is giving permissions that join it with the permissions available to some other origin (those of the page in which the iframe is embedded being the most strongly implied). This is not the case. The token would have been more appropriately called allow-keep-original-origin, or something similar.

What the allow-same-origin token does is permit the page inside the iframe to retain the origin which it originally has as a result of being loaded from the URL it came from. That means that an iframe like <iframe src="http://example.com/" sandbox="allow-same-origin allow-scripts"></iframe> is permitted to run scripts and behave as if it's origin is http://example.com, nothing more than that. It does not expand that origin to that of the containing page. If the allow-same-origin token was not present, then the iframe would behave as if its origin was something like fooscheme://someTotallyUniqueOriginThatWillNeverMatchAnythingElse027365012536.yeahWeReallyMeanItWillNeverMatch (i.e. an origin that is guaranteed to never match anything else, even itself).

So, despite the name of the allow-same-origin token, it does not grant any additional special capabilities which the iframe would not otherwise have, except that it gets to retain its original origin.

Using the allow-same-origin token permits the code in the iframe to use things like cookies, DOM storage (e.g. localStorage), IndexedDB, etc. like it normally would when loaded from its original origin. Including the allow-same-origin token will be necessary for many web pages to have something close to normal operation.

I found MDN's statement on allow-same-origin:

Allows the content to be treated as being from its normal origin. If this keyword is not used, the embedded content is treated as being from a unique origin.

to be somewhat helpful in understanding this. The blog post "Play safely in sandboxed IFrames" helped a bit. The statement in the W3c HTML 5.2 specification was also helpful [emphasis mine]:

The allow-same-origin keyword is intended for two cases.

First, it can be used to allow content from the same site to be sandboxed to disable scripting, while still allowing access to the DOM of the sandboxed content.

Second, it can be used to embed content from a third-party site, sandboxed to prevent that site from opening pop-up windows, etc, without preventing the embedded page from communicating back to its originating site, using the database APIs to store data, etc.

And the additional information from the W3C HTML 5.2 specification (the sandboxed origin browsing context flag will be set unless the allow-same-origin token is present):

The sandboxed origin browsing context flag

  • This flag forces content into a unique origin, thus preventing it from accessing other content from the same origin.

  • This flag also prevents script from reading from or writing to the document.cookie IDL attribute, and blocks access to localStorage. WEBSTORAGE

MDN's page on Same-origin policy was also of interest.

like image 115
Makyen Avatar answered Oct 24 '22 23:10

Makyen