LavaMoat / LavaDome

Secure DOM trees isolation and encapsulation leveraging ShadowDOM
https://lavamoat.github.io/LavaDome/packages/core/demo/
MIT License
16 stars 3 forks source link

Defend from extension content scripts #41

Closed NDevTK closed 2 months ago

NDevTK commented 2 months ago

Unlike the background worker, content scripts should not be exposed to sensitive information.

    function shadow(e) {
        if ('openOrClosedShadowRoot' in e) {
            // Firefox
            return e.openOrClosedShadowRoot;
        } else {
            // Chromium
            return chrome.dom.openOrClosedShadowRoot(e);
        }
    }

"One use case for such a feature is MetaMask's "show private key" toggle, which exports the private key into plaintext upon user request." this is from a browser extension right? so can just use the API.

NDevTK commented 2 months ago
(() => {
 let frame = document.createElement('iframe');
 frame.sandbox = '';
 document.body.appendChild(frame);
 frame.contentWindow.location = 'data:text/html,This is a secret!';
})();

I don't really get what's so hard about using an iframe

NDevTK commented 2 months ago

Like the ShadowDom could just use an iframe internally :) Needed CSS can be passed in, after its checked to be safe from leaks.

weizman commented 2 months ago

Thank you for engaging with this project @NDevTK. A couple of points:

Unlike the background worker, content scripts should not be exposed to sensitive information.

That's not true really.

Not only that they should according to the most basic rules in runtime security ("first to run overpowers others" and "extensions, whether background or content-scripts, are superior to app context"), but also that there's nothing that can be done about it with current state of the web. If you execute JS code before LavaDome, whether as content script or as just plain JS in the app, you always have the power to compromise LavaDome and there's nothing we can do about it (as we learned over and over with Snow with which you are very familiar).

Therefore, code running before LavaDome is out of its threat-model scope by definition. We make that very clear in the README.

"One use case for such a feature is MetaMask's "show private key" toggle, which exports the private key into plaintext upon user request." this is from a browser extension right? so can just use the API.

Not exactly.

Yes, MetaMask is an extension, but LavaDome is deployed within the web app of MetaMask itself, and not into web pages the MetaMask extension has access to. Therefore, the openOrClosedShadowRoot API cannot be used against how MetaMask deploys LavaDome.

In contrast to this, if a normal web app decides to deploy LavaDome, installed extensions can compromise LavaDome using the openOrClosedShadowRoot API.

Again, according to the threat model, that's possible by definition. LavaDome can't do anything about it, and therefore won't try.

If I ever encounter an example for successfully defending hermetically against all types of attack attempts carried by code running BEFORE the defender - I will admit to be wrong, and this will change how runtime security is handled and perceived DRAMATICALLY (cc @SMotaal).

"I don't really get what's so hard about using an iframe"

Against content scripts? Or same-privileged entities within the app? Not sure which one you mean so I'll address both:

With content scripts, this approach is not superior to ShadowDOM in any way, because again - they can run code before LavaDome that easily undermines it (whether by tapping into createElement, 'appendChild`, or anything else).

Also, extensions can instruct the browser to load their content script within every new realm, so the "sandbox" attribute won't really save you here from extensions.

With same-privileged entities within the app, you are not wrong. An iframe can introduce security and it was considered carefully when initiating this project (and still is).

The problem with iframes however, is that they make it harder (not impossible) to integrate generically into apps while maintaining the same level of UI/UX as opposed to ShadowDOMs.

"Needed CSS can be passed in, after its checked to be safe from leaks."

This is what I'm talking about. This isn't something simple to do. Expecting others to adopt LavaDome is far harder when they have to provide CSS to make the app behave as smoothly as without it, especially if LavaDome introduces text that runs within a separate realm (iframe).

To this complexity, add the need for LavaDome to introduce CSS sanitization logic that is trustworthy which would probably require us to maintain continently.

This makes iframes far less desirable as the tool for the job IMO. You can find more information about this in the README.

I made sure to address your input entirely and with details, I hope this helps.

NDevTK commented 2 months ago

"CSS sanitization logic that is trustworthy" seems the same as ShadowDOM but when its cross-origin you have more control over the sanitization. There is also meltdown+spectre concerns to leak information since its all in the same process.

"first to run overpowers others" does also apply to content scripts (if you own them) but yeah a normal web app is better to protect from.

"code running before LavaDome is out of its threat-model" for browser extensions it is possible to deny them from accessing a host even if they ask for <all_urls> this is with a feature called runtime_blocked_hosts https://support.google.com/chrome/a/answer/9867568 but it does require a policy to be set people can opt-in to this protection if they want to.

weizman commented 2 months ago

Fair point. I still think using iframes would be far harder. Might get convinced one day in the future.

Closing for now (feel free to reopen if needed)