In light of some feedback we've received on the article, some
clarification is needed. The ocap (object-capabilities) approach does
not by itself make systems secure. Rather, it an enormous step
towards making systems secureable. Even after taking this step, making
complex systems secure can still be very hard, depending on the
specifics.
In an ocap system such as SES https://github.com/Agoric/SES , an
object can only directly cause effects on the world outside itself by
using the capabilities it holds. Objects come in graphs held together
by references, so an object can still only cause effects, directly or
indirectly, according to its connectivity to the rest of the system
via references. The different between direct effects vs general
causation is the difference between permission and authority
[1,2]. Permission is often vastly easier to reason about than
authority, but our safety depends on reasoning about limits on
authority.
The event-stream exploit would have been prevented merely by practicing
the principle of least permission. Hence this article did not need to
go into these subtleties. Hence, this exploit is a good example for
introducing people to these concepts, tempting them to dig deeper [3].
This npm / event-stream incident is the perfect teaching moment for POLA (Principle of Least Authority), and for the need to support least authority for JavaScript libraries.
What would be the sane behaviour for the following situation?
my app imports an http request library and gives it net permissions
my app imports a templating library and gives it no permissions
the templating library is malicious and tries to import well known http request libraries, and finds the one i imported, which has been given net permissions.
or what if you give the templating library a mixin of some sort which accidentally exposes the privileged http library
This is a really good question. You would want to ensure that the templating library cannot get access to the http request library unless the templating library is explicitly given a reference to it. So even though both libraries are imported, they can't access each other by default. Realms (the standards track proposal [1]) lets you do this, and Salesforce uses it right now as the security kernel that ensures that their third party apps can't view or mess with other apps [2].
The best way to enforce POLA, and especially this particular problem of not allowing libraries to have access to each other, is object capabilities (ocaps) [3]. An object capability combines designation with authority -- if you have access to a capability, you can use it. If you don't have access, you can't use it. You can think of this (very roughly) as a key to a car as opposed to your name being on a guest list for a party. I didn't really touch on ocaps in this piece, but it's a necessary component for being able to enforce POLA well.
Worth noting that the principle of "a package can only access the dependencies it declared" is already something that we (Yarn) are pushing through Plug'n'Play.
We're not focused on security (yet), but any help we can get to move the ecosystem towards a stricter model will help you in the long term (by ensuring that common tools will be compatible with the even stricter model you're advocating).
The SecurityManager is an example of ambient authority, exactly the kind of design that the article is criticizing.
There's at most one SecurityManager per application, meaning you can't in general use it for fine-grained confinement. It's only "granular" in the sense that requested permissions can be arbitrarily finely subdivided. There's no notion of intra-application invocation contexts, making it vulnerable to "confused deputy" problems, including things like the event-stream incident.
At https://twitter.com/spudowiar/status/1069680974110306306 Saleem Rashid raises an example of this principle that is especially easy to overlook, where authority arises from one entity relying on the unchecked veracity of another.
In an ocap system such as SES https://github.com/Agoric/SES , an object can only directly cause effects on the world outside itself by using the capabilities it holds. Objects come in graphs held together by references, so an object can still only cause effects, directly or indirectly, according to its connectivity to the rest of the system via references. The different between direct effects vs general causation is the difference between permission and authority [1,2]. Permission is often vastly easier to reason about than authority, but our safety depends on reasoning about limits on authority.
The event-stream exploit would have been prevented merely by practicing the principle of least permission. Hence this article did not need to go into these subtleties. Hence, this exploit is a good example for introducing people to these concepts, tempting them to dig deeper [3].
[1] Paradigm Regained http://www.erights.org/talks/asian03/paradigm-revised.pdf
[2] Permission and Authority Revisited https://ai.google/research/pubs/pub45570
[3] References page https://agoric.com/references/