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.
To fix the issue to to Settings > Privacy > Content Settings change the cookies settings to Allow local data to be set
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 calledallow-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 ishttp://example.com
, nothing more than that. It does not expand that origin to that of the containing page. If theallow-same-origin
token was not present, then the iframe would behave as if its origin was something likefooscheme://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 theallow-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
: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]:
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):MDN's page on Same-origin policy was also of interest.