Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Hardening EPUB content in iframes #120

@chocolatkey

Description

@chocolatkey

EPUB content, as is valid per the latest EPUB spec, is inherently dangerous as creators of EPUB files have the ability to take full advantage of the web browser's HTML, CSS and Javascript engines. With the way the ts-toolkit is currently implemented, it is an easy task for EPUB content in an iframe create and managed by the toolkit to escape and execute malicious JS on the parent frame. Any data in localstorage, or cookies that are not fully secured, are fair game, as well as other behavior such as deceptive UIs, tracking of user data, location etc.
While most large users of the ts-toolkit will be receiving their publications from trusted sources, this is not always the case, and we should not expect users of the toolkit to be aware of all the risks that come with accepting user-generated content in their web reader. Therefore, we should take the necessary steps to lock down content as much as possible by default, possibly providing ways to disable these protections if explicitly specified.
The EPUB spec lists some of the concerns here: https://www.w3.org/TR/epub-33/#sec-security-privacy
Here is an EPUB the author of foliate made to test many of the security issues: https://github.com/johnfactotum/epub-test/tree/master
I think we should take a stricter approach by default than what is allowed in the EPUB spec, as simply loading an external image gives the host of that image the ability to track your approximate location (IP address), web browser, and more.
Personally, I would suggest we completely disallow the loading of remote resources by default. And even if this is explicitly enabled by the implementer, it should be contingent on some sort of property in the webpub manifest, which I would suggest porting over from the original EPUB.

I have done some experimentation with the ts-toolkit to see what we can do to secure things. Here is what I've come up with so far we could do (note this still restricts some stuff that is allowed in the EPUB spec):

Injecting CSP into the iframe

During the building of the iframe content, we already inject tags into the <head> of the document. The Content Security Policy can be injected not only using HTTP headers (which is very difficult for us to do), but also by using a <meta> tag in the head of the document. I have tried this out, and it seems to be pretty effective. Example code snippet:

// FrameBlobBuilder.ts
// root = the base path of the publication

const csp = (domains: string[]) => {
    const d = domains.join(" ");
    return [
        // 'self' is useless because the document is loaded from a blob: URL
        `upgrade-insecure-requests`,
        `default-src ${d} blob:`,
        `connect-src 'none'`, // No fetches to anywhere.
        `script-src ${d} blob: 'unsafe-inline'`, // JS scripts
        `style-src ${d} blob: 'unsafe-inline'`, // CSS styles
        `img-src ${d} blob: data:`, // Images
        `font-src ${d} blob: data:`, // Fonts
        `object-src ${d} blob:`, // Despite not being recommended, still necessary in EPUBs for <object>
        `child-src ${d}`, // <iframe>, web workers
        `form-action 'none'`, // No form submissions
        //`report-uri ?`,
    ].join("; ");
};

// Add CSP
const meta = doc.createElement("meta");
meta.httpEquiv = "Content-Security-Policy";
meta.content = csp(root ? [root] : []);
meta.dataset.readium = "true";
doc.head.firstChild!.before(meta);

Setting the sandbox value for the iframe

Unfortunately we cannot make this super strict, but setting sandbox="allow-same-origin allow-scripts" on the iframe does add some protections

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions