Open caridy opened 2 months ago
IMO the context of the proposal makes this pretty clear, but no harm in explicitly stating so - mind approving? https://github.com/WICG/Realms-Initialization-Control/pull/36
That PR makes it clear. Now, the concern is how the top realm will gain or hold some of these capabilities that are going to be denied to child realms. This sounds a lot like the same trap we felt into with CSP, where everyone must play by the same rules, which hinders the ability to adopt it because it is too hard. Hence we end up with Trusted Types to open the door for someone to have a magic wand and gain additional capabilities that are otherwise denied to the rest of the code. E.g.: I will like to deny access to the session id from cookies or something like that for child realms, but I will like to still have access to it as part of my app, how to achieve this?
Well, since this feature is designed to allow code-based customization of behaviour of capabilities, I guess JS's expressiveness comes into play here. At the most basic level, the reconfiguration of the APIs can take such differences into account:
// Content-Security-Policy: init-realm: /init.js
if (window !== top) {
const block = () => { throw 'BLOCKED' }
defineProp(window.document, 'cookie', { get: block } )
}
Combined with other web capabilities, my vision is that such getters will determine whether to grant access to a capability or not (and to what extent) based on whether the entity asking for it is permitted to (should script coming from src X be allowed to access capability Y? should DOM node A be allowed to walk through to DOM node B?).
While difficult, this vision is very much possible in user land. The only blocker in achieving that is the same origin concern which would be solved when this proposal lands.
Oh, no, I don't think that works because of the undeniable. The code snipped above, where cookie is only really blocked for child realms, while they have access to top.document.cookie just fine via the undeniable top
accessor. That's the thing, for this to work, you only have to paths, and both are very difficult paths:
In essence, this is the same dilemma as trusted types, where there is a magic wand, and if you manage to get your hands on the magic wand, you can do wonders, otherwise, you are at the mercy of the capabilities allowed by CSP.
Via the undeniables, access to the reconfigured descriptors will always be possible, this proposal won't focus on that problem. However, having access to a descriptor, does not mean the descriptor would necessarily provide the capability to anyone that asks for it.
"The code snippet above" does not demonstrate that by itself, but only together with the paragraph that comes right after it about "web capabilities", which should result in something more sophisticated:
// Content-Security-Policy: init-realm: /init.js
if (window !== top) {
const block = () => { throw 'BLOCKED' }
defineProp(window.document, 'cookie', { get: block } )
} else {
const mitigate = () => {
const entity = whoIsAskingForDocumentCookie()
if (!allowedEntitiesToAccessCookie.includes(entity)) {
throw 'BLOCKED'
}
return realCookie
}
defineProp(window.document, 'cookie', { get: mitigate } )
}
And based on your (correct) take, this is the former of the two suggested paths - it's very hard telling who's asking for a capability in a safe way, but with some hard R&D it is possible (proxies also helped a lot in paving that way).
It's also important to mention that the RIC proposal makes sense in slightly different context as well, for example, what if we want to compose a monitoring system that only monitors consumption of powerful capabilities instead of mitigating them? For that, the same redefinition can take place for both the top and the rest of the realms, so that this problem doesn't apply anymore:
// Content-Security-Policy: init-realm: /init.js
defineProp(window.document, 'cookie', { get: () => {
reportToServer({msg : 'cookie was accessed' })
return realCookie
} } )
So it's really a matter of use case, but all in all, having a power such as RIC would allow builders to ship control over capabilities their app provides - a great and important accomplishment from my perspective.
I think whoIsAskingForDocumentCookie
in the example above is the problem. In the web, as it stands, it is impossible to know who is calling when it comes to undeniables. My recommendation is to attempt to either remove or perhaps relax the "traversal undeniables" (maybe making top
and co. configurable/non-writable) so RIC can distort their behavior as well.
In the web, as it stands, it is impossible to know who is calling when it comes to undeniables.
I don't see the problem you're referring to, if you get a chance to elaborate on this
From the following paragraph:
It is not clear if the
monitor.js
script will get executed in the root realm or not. From the readme, it seems that it only applies to other child realms, because otherwise you have no way to gain access to those capabilities (e.g. fetch) in the root realm, but then I see no references to the undeniables.Here is a concrete example:
Let's assume that the new header points to
remove-fetch.js
to prevent child realms to access fetch global value all together. Then the attacker does the following:Specifically, the problem I see here is that
remove-fetch.js
has no way to replace/tametop
because it is undeniable, and since it does not run in the root realm, the fetch fromtop
is going to have full capabilities.Note: this is not a problem when creating new ShadowRealm instances because they don't have undeniables.