Grasping these core concepts is important for fully understanding the power of Intrinsic and how it can be used to protect your applications.
Principle of Least Privilege
Intrinsic secures your application by following the Principle of Least Privilege (sometimes referred to as the Principle of Least Authority). Simply put, this principle requires that any code only has access to exactly what it needs in order to complete its task.
Every program and every privileged user of the system should operate using the least amount of privilege necessary to complete the job.
—Jerome Saltzer, Communications of the ACM (1974)
By default, a Node.js application is able to do anything that it wants to. For
example, it can make outbound HTTP requests to websites owned by a hacker. It
can read the contents of the
/etc/passwd file (depending on your OS
filesystem permissions). It can connect to your MongoDB database instance and
issue as many
delete commands as it would like.
Of course, your application probably doesn't need to perform those actions. Even though you haven't programmed your application to perform those actions, they can still happen either when a logical error is introduced into the code or if a malicious actor is able to take control of the process and tell it what to do. See our post The Dangers of Malicious Modules to see how feasible such an attack is.
Intrinsic sets up several user-defined sandboxes within the
language runtime and then runs application code within those sandboxes.
Intrinsic restricts each sandbox so that they are only able to perform the
exact privileged operations which have been whitelisted ahead of time. So, if
a sandbox does need to delete from a database, which might have been associated
with an HTTP route such as
DELETE /api/users, then only this route's sandbox
will be able to delete a user from the database.
By following the Principle of Least Privilege, Intrinsic is able to provide a high standard of security for applications. Other approaches, such as heuristic or blacklist-based security, will result in a messy game of cat and mouse.
Intrinsic is able to lock down application code to follow the Principle of Least Privilege, the security gold standard which—until now—has proven hard to achieve. By writing security policies using application code, Intrinsic is given the necessary context to write fine-grained policies.
Each sandbox is essentially a separate running instance of your application with its own set of policies applied to it. Sandboxes are usually broken down on a per-route basis—except for lambda and any future serverless environments we support, which will only require a single sandbox.
These separate sandboxes aren't entirely like browser tabs, i.e. they typically
run within a single thread (though we do have an advanced multiprocess
mode). Sandboxes are separated in
the sense that each sandbox has its own isolated object tree. Consider, for
example, the damage that can be done by modifying the global
prototype. Doing so normally has widespread implications which affect the
entire application. With Intrinsic, each sandbox has their own isolated object
prototypes, and such implications are no longer present.
Because each sandbox has different permissions it's important that they cannot
communicate with each other. For example, consider a situations where sandbox
A is able to send data to a third party, and sandbox
B is able to read
important service credentials. If an attacker is able to execute arbitrary code
within the application then the credentials cannot be sent to the third party.
However, if sandbox
B is able to write to a file which sandbox
A is able to
read from, then an attacker could conceivably use this as a side channel to
transmit the information along. Of course, this is a bit of a stretch, as it
would require a highly targeted attack where the attacker is aware of the two
sandbox situation, and is aware of the exact overlap in policies.