edrlab / thorium-reader

A cross platform desktop reading app, based on the Readium Desktop toolkit
https://www.edrlab.org/software/thorium-reader/
BSD 3-Clause "New" or "Revised" License
1.73k stars 151 forks source link

Programmatic window.location redirection to external URLs, plus other security considerations #1375

Closed danielweck closed 2 years ago

danielweck commented 3 years ago

Jotting down some thoughts ...

Background information:

@johnfactotum ( https://github.com/johnfactotum/foliate ) created an EPUB to test potential security holes in reading systems: https://github.com/johnfactotum/epub-test ...which was recently mentioned in this Bookworm discussion: https://github.com/babluboy/bookworm/issues/283#issuecomment-686926109

A few years ago I created a test for window.parent and window.top security breaches, but the scope of this test recipe was quite narrow (e.g. no fetch() or XmlHttpRequest tests for local file access): https://github.com/danielweck/epub-reading-system-js-sandbox-test

Note that window.frameElement.ownerDocument.defaultView.location is another attack vector, and window.parent / window.top accessors can be monkey-patched by reading systems only if the object properties are not readonly.

A well-configured HTML5 sandboxed iframe effectively protects against such maliciously-authored publication content, so do CSP (Content Security Policy) + smart usage of web origins in the reading system's client/server architecture.

Useful references:

Leonard Rosenthol's research: https://lists.w3.org/Archives/Public/public-epub-wg/2021Feb/0007.html

EPUB specifications: https://github.com/w3c/epub-specs/issues/873#issuecomment-246765067 https://github.com/w3c/epub-specs/issues/1156

Topic to investigate:

Thorium uses a strict Electron webview sandbox (i.e. out-of-process iframe embedded in a shadow DOM) to host EPUB XHTML content documents. Thorium also ensures that the NodeJS runtime does not leak into them (this would otherwise be catastrophic from a security standpoint). Note that like all reading systems, Thorium injects CSS and Javascript into guest XHTML documents, in order to implement annotations, media overlays, search highlights, pagination, hyperlinking hijacking, the epubReadingSystem object, etc. However, unlike a web reader which has a limited number of options to achieve this (some with significant caveats, such as not sandboxing the embedded iframes at all, srcdoc, blob URIs, document.write(), even postMessage which causes its own problems due to its async nature, etc.), Thorium leverages an Electron-specific mechanism (webview preload script) which guarantees that access privileges are in one direction only. Thorium also injects features ahead of time at the server level (aka HTTP "streamer", or its non-HTTP equivalent). Most importantly, Thorium configures a single origin per publication in order to isolate "state"-related APIs (localStorage, indexedDB, cookies, service worker caching, etc.) and consequently to prevent unintentional or malicious cross-publication information "sharing".

Using John's EPUB, I was reminded that although we allow programmatic window.location redirection to publication documents (because this is a hyperlinking method sometimes found in EPUBs generated by "inDesign"), we do not seem to allow that pattern for external websites. Yet, we allow user-triggered external hyperlinking by delegating the actual opening of the link to the default web browser on the user's OS. At first glance this is arguably a good design choice, because programmatic APIs can be abused, whereas user interaction normally correlates with user intent. However a malicious script could easily emulate user events to trigger hyperlinks (unlike automatic audio/video playback which is more strictly controlled by browser engines), so that may be a moot point.

Logistical point: this issue should probably be moved to a GitHub discussion.

danielweck commented 2 years ago

I tested https://github.com/johnfactotum/epub-test with the latest Thorium release (v1.7.2) which ships with Electron v14, no HTTP server (instead: custom URL protocol handler with HTTP privileges / security constraints), same Content Security Policy as before on embedded webview controls, and the re-enabled programmatic navigation interceptor (e.g. InDesign Javascript-controlled hyperlinks). Everything works as expected. I am closing this issue as this is not actionable as a bugfix / feature / etc.