7 ms·
Deno core team member and TC39 delegate here. We have pondered about capability based security for Deno in the past. Our conclusion has always been that this i
by lucacasonato 5y ago
Deno core team member and TC39 delegate here.
We have pondered about capability based security for Deno in the past. Our conclusion has always been that this is not possible to do securely in JS without freezing all prototypes and objects by default. The reasoning for this is that you need to make sure the capability token does not ever leak. For example as a malicious user I could override `globalThis.fetch` to exfiltrate the capability token destined for `fetch` and use it myself later.
One could also override `Map.prototype.set` / `Map.prototype.get` to exfiltrate a token every time it is added or removed from a `Map` (people will want to store tokens in a `Map`).
One could also override `Array.prototype[Symbol.iterator]` to exfiltrate tokens stored in arrays if those arrays are destructored, spread, etc.
There are many more cases like this, where one can exfiltrate tokens because of the very dynamic nature of JavaScript.
It is unlikely that freezing all intrinsic prototypes and objects is even enough. People will find ways to exfiltrate tokens.
- zozbot234 5y agoThese seem like features that could work a bit better in the context of WASM modules and/or components. AIUI, WASM was designed with the expectation that support for capabilities would be required.
- lucacasonato 5y agoYup, for sure. I think capability based ShadowRealms are also totally doable. I'm sure we'll add those for Deno once we add support for ShadowRealms.
- 3np 5y agoDoesn't SES address that? The only fundamental barrier right now seems to be performance, which could be addressed by runtime support. https://github.com/tc39/proposal-ses https://github.com/tc39/proposal-ses https://github.com/endojs/endo https://github.com/endojs/endo
- lucacasonato 5y agoYup, SES would address this. But SES also needs to bring with it a paradigm shift for JS: a) Folks would have to load each bit of code they want separate permissions for in a separate compartment. This won't be easy. b) Runtimes will need to provide an immutable global realm, which is not something that is the case right now. As I said in a different commeent, I think a lot of this can already be addressed by ShadowRealms. Deno will likely allow users to specify per ShadowRealm permissions, which is probably as granular as most people will want to get.
- naugtur 5y agoThere's Endo, which does the loading/importing and dependency resolution. It doesn't have a default user experience at this point, but it creates compartments for packages and runs. Getting permissions involved will require mapping them to packages in a policy file and there you go - an environment where you can use packages and they can't surprise you with data exfiltration etc.
- naugtur 5y agoAlso, what's shadow realms? I tried looking it up and got a video game. And I'm not much of a gamer so it's not a matter if a bubble ;)
- robotnikman 5y agoI think they might be talking about this https://github.com/tc39/proposal-shadowrealm https://github.com/tc39/proposal-shadowrealm ShadowRealm is possibly a reference to the Shadow Realm from the card game Yu-Gi-Oh
- danfinlay 5y agoThere's LavaMoat, which enables using SES confinement around normal npm packages by creating a policy file for what can be imported/required by that module (and can auto-generate a suggested policy file from what appears used, which fails to greater restriction/security, and can easily be expanded): https://github.com/LavaMoat/LavaMoat https://github.com/LavaMoat/LavaMoat
- prakis 5y agoWhy not lock the core libs like Map.prototpy Array.prototype ? Can't we have sandbox like environment (which is not default but which can be enabled on application basis). Java Applets which run inside the browser had this kind of sandbox restritions.
- white_dragon88 5y agoWhy not just freeze anyway? At the end of the day you don’t know what you don’t know. Deno is well positioned to make these sorts of restrictions, how often is someone doing something as mental as modifying prototypes in a nodejs environment anyway? (Moment comes to mind actually, but does it really matter? That library is deprecated anyway)
- yonixw 5y ago> something as mental as modifying prototypes This is exactly what Jest (mocks) is built on top of. You will fail every enterprise security scan if you have Jest in the production package/docker.
- lucacasonato 5y agoIf it was 2000, or even 2010, I'd agree with you. But that ship has unfortunately sailed. People modify the prototype all the time. If we were to freeze all prototypes right now in JS, a lot of existing code would break.
- joshAg 5y agoPart of the draw of deno is that for better or worse it's javascript. If you start changing things about the language used in the deno runtime such that it's no longer compliant ecmascript, then you no longer get the benefits of it being ecmascript. The devs' mental modal of the language isn't a drop-in, libraries and modules including popular ones, are no longer guaranteed to work out of the box, etc. You might say that all that is worth the benefit, but in that case why not just use another language that already gives you the feature you want or why stop there? Why not also fix other issues with javascript at the same time since we're no longer preserving compatibility? Something mental like the automatic type coercions? Or getting rid of var?
- bakkoting 5y agoDeno has already made similar changes, like https://github.com/denoland/deno/pull/4341 https://github.com/denoland/deno/pull/4341. That particular change happens to be allowed by the JS standard. The change discussed here isn't currently allowed, but I suspect TC39 would be open to making it allowed (though obviously it would not be allowed for browsers, in the same way the linked change to __proto__ is not allowed for browsers). If you change something that most code isn't relying on, most code will still work. This change is plausible because it's very rare for code to be mutating built-ins. That's not true for most other possible "fixes". And most other changes would not have a benefit to consumers of the application (who cares if the library you're using has `var`s?), so they're much less well motivated.
- akhmatova 5y agoYour input is appreciated. But to anyone not using JS on a daily basis, the above reads as a blur of detail, rather than a clear, actionable message about to do about the overall situation. So I'd be curious to know if you have a holistic response to primary claim made by the post, which is: The fundamental problem with npm is that any package you install has full access to do whatever it wants on your computer.
- yonixw 5y agoBased on your use-case, it may already been solved. Microservices, for example, are put in a container, which allow you to give read-only\full access to selected files. They also usually have some kind of Mesh side container that limits connectivity between whitelisted containers or public DNS. And since containers can limit memory and throttle CPU, you are more or less at the best you can get using untrusted 3rd party code.
- armchairhacker 5y agoDynamic languages such as JS allow you to override almost anything. It’s essentially impossible to sandbox “part” of JS code, you must either sandbox the entire runtime (e.g. in browsers) or allow everything (e.g. in node.js). Individual packages want to run arbitrary JS code to do “safe” things during installation. But it’s very hard to allow them to do anything meaningful like file access, even if it’s “safe”, without potentially allowing exploits.
- throwawayboise 5y agoRun in a chroot/jail or container?
- lucacasonato 5y ago> The fundamental problem with npm is that any package you install has full access to do whatever it wants on your computer. Let me try to answer more concisely at a higher level: Due to JS being a very dynamic language, it is at this time not possible to give different packages inside of the same JS runtime a different set of permissions or capabilities securely. Because of this, the best we can do for sandboxing right now is permissions / capabilities that are set per JS runtime, rather than per dependency / module. This is what Deno does. It allows you to set capabilites for the set of your code and all of it's dependencies at once. If you want to run a certain module with lesser permissions, you need to move it into a seperate JS runtime, either by running it on a seperate thread with a web worker, or in a seperate Deno process. Both web workers and subprocesses can have different (lesser) permissions to their parent.
- inglor 5y agoHey luca, I assume you are familiar with Mark’s extensive work on capability based security for ES?
- lucacasonato 5y agoYup, SES is very interesting, and I think it can solve this problem in the future. As this post is about the here and now though, and SES is not yet ready for widespread adoption, I think my point stands that at this current time it is not possible to securely do capability based security in JS.
- throw_m239339 5y agoHi, first thanks for your work both in TC39 and Deno. But that's not the heart of the problem for node. The problem with node ecosystem and is a combination of a refusal from Core to provide a meaningful standard library, a set of packages people can trust so they don't have to download random things from the internet just to parse the body of a multi-part request for instance, and the fact that NPM was badly architectured as it's going to fetch as many versions of a same package as it needs to solve dependencies. Good package managers don't do that, period. Of course that, given the dynamic nature of Javascript, anybody can monkeypatch anything. But the language itself isn't at fault, it REALLY IS both the politics of a paper thin STD lib and bad package management with stupid dependency resolution. And frankly Node.js should stop shipping with a package manager and its infrastructure entirely controlled by Microsoft. it's so bizarre how nobody seems to mind that in the Node community... NPM servers aren't open source.
- ex3ndr 5y agoYou can do this in almost any language, like Java, ObjC/Swift, etc
- voxic11 5y agoand I don't think any of those languages support capability based security either.
- bakkoting 5y agoo/ Luca! Fellow TC39 delegate here. > It is unlikely that freezing all intrinsic prototypes and objects is even enough. People will find ways to exfiltrate tokens. This is probably true, but frozen intrinsics would make it a _lot_ harder. Right now it's not reasonable to ask a library to be defensive against capability exfiltration, since it means not using any built-ins, but I think with frozen intrinsics it would be reasonable to treat a library leaking its capabilities as a security bug. There would still absolutely be leaks - most significantly in libraries which export classes and don't freeze the class prototype - but things would no longer be completely insecure by default. It would make malicious code have to work a _lot_ harder. I think it's worth a shot. Deno removed the __proto__ getter/setter, and that did require a bunch of libraries to update, but it worked out OK. Node already has --frozen-intrinsics, if anyone feels like experimenting with whether that would break your code.
- lucacasonato 5y agoYeah, I agree it is definitely worth trying! I think all the talk around SES will push JS as a whole further towards something that could support capability based permissions securely in the future.
- mrtweetyhack 5y ago
- jollybean 5y agoThe notion of 'securing part of a runtime' is essentially a fallacy. 'Sandboxing' anything really is quite hard. If you want to make a firewall between blocks of untrusted code, they have to be run in completely isolated from one another, which creates a lot of overhead. I don't see anyway to mix untrusted with trusted code. If some of your code is untrusted, it's all untrusted. We probably need an operational situation to this, which is, you pay a fee to some org that literally sits there and pours through the code to look for hacks, and there's some verification & oversight a to who is submitting what. etc.. It may very well be that the days of regular open source are over, there might have to be some changes to it. I can imagine in 10 years from how, all you telling junior devs about the 'good old days' when people just randomly put some code up on a site, and you used it! They will hardly believe you. "That's crazy, a few line of bad code could wipe out your company!".