Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider FULLY sandboxing and isolating the iframe (remove allow-same-origin) #986

Closed
Jaifroid opened this issue Apr 17, 2023 · 7 comments
Closed

Comments

@Jaifroid
Copy link
Member

Jaifroid commented Apr 17, 2023

The advantage of fully isolating/sandboxing the iframe becomes evident with Manifest v3 of the webextension specification. If the sandbox is fully isolated, i.e. if it does not allow-same-origin access, then it is possible to relax the CSP within the iframe, e.g. by allowing unsafe-inline and unsafe-eval. See https://developer.chrome.com/docs/extensions/mv3/sandboxingEval/ for a full explanation of the advantages. Something like this will be necessary if we are to add Zimit support to Kiwix JS and still support Manifest v3. Many Zimit sites will use unsafe-inline code, because they have not been specifically tailored for ZIM usage (see #865), and many may rely on frameworks that will have unsafe-eval code.

The big DISADVANTAGE of this approach is that the only way to access a fully isolated iframe (one which does not allow-same-origin) is via post messaging. It would be necessary to have a small application in the iframe to receive the messages and display the HTML. It might be necessary for the iframe to spawn another iframe in order to separate the ZIM contents from the application. This implies a significant re-engineering effort, and it's not possible to tell how well it would work without undertaking quite a lot of that re-engineering.

@Jaifroid
Copy link
Member Author

Having said that, libzim currently works entirely via post messaging a Worker, so some of the messaging infrastructure is already in place (but not the method of populating an isolated iframe).

@Jaifroid
Copy link
Member Author

Using Shadow DOM may be the best way to isolate the displayed document from the application that receives the post messaging. This implies limiting it to modern browsers. However, if this is primarily for Manifest v3 support, then that is not an issue.

@Jaifroid
Copy link
Member Author

Jaifroid commented Apr 20, 2023

We would need an initial script attached to article.html that would listen for messaging from the app in order to load the landing page into the iframe when the ZIM is first opened. We would subsequently need to handle the Random button and the Home button in the UI, potentially also the back and forward buttons (possibly by reloading article.html). Other than those, the Service Worker should simply handle natively any request for an article from within the iframe, as well as requests for assets. So any application could be really simple.

We can't assume that an article loaded into the iframe is always HTML, so we still need a way to isolate the messaging application from the document displayed, but all within the same sandbox. Shadow DOM might do it, so long as any document loaded from the Shadow DOM stays in the Shadow DOM, and doesn't overwrite the whole iframe, and so long as the Shadow DOM is accessible via scripting...

@Jaifroid
Copy link
Member Author

Some of the challenges of using Shadow DOM instead of iframes are described here: https://medium.com/bbc-product-technology/goodbye-iframes-6c84a651e137.

@Jaifroid
Copy link
Member Author

Jaifroid commented Apr 23, 2023

Experiments with Manifest v3, specifically this commit, show that we wouldn't be able to do this simply by setting the src of a nested iframe to the URL of the article. This is considered cross-site scripting with a user-provided value, and is blocked. The sandbox with liberal CSP only works with URLs specifically provided in the app manifest, and it seems that nested iframes are not exempt. This is not a solution for us, and it means we'd have to inject the HTML directly into the iframe's DOM (which also might not work).

@Jaifroid
Copy link
Member Author

Using Shadow DOM appears not to be an option because there is no way to specify a base URI for elements in the DOM. This means that there is no way to recognize URIs called from the ZIM as opposed to URIs that are part of the app, now that we no longer have a namespace exposed in the ZIM. See this commit: setting either base href in the injected HTML, or baseURI in the iframe document are both ignored. See Also https://www.w3.org/TR/2017/WD-shadow-dom-20170905/#inertness-of-html-elements-in-a-shadow-tree, where it specifies that base must not be obeyed in a Shadow DOM.

Neither is it possible to navigate an iframe elsewhere after loading article.html. This gets actively blocked by the browser.

@Jaifroid Jaifroid added wontfix and removed question labels Apr 30, 2023
@Jaifroid
Copy link
Member Author

Turns out to be a major piece of re-engineering to fix this, for little gain when we have a better solution #992.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant