Conventional programming languages give too much power to programs. Typically, any program is potentially capable of doing anything that the whole system is capable of doing. This makes sense to programmers because programmers want powerful tools. But it shouldn't make sense for anyone else because such inappropriately powerful systems are unable to adequately defend themselves against malicious or imprudent programs. Attempts to add security features to existing systems have proven to be sadly and painfully and expensively ineffective. Archaic measures like file permissions are based on the assumption that individuals are responsible for the security properties of the programs they run. Security management software that alerts the user to potentially dangerous actions are worse than ineffective: Most people can not possibly be expected to know how to correctly respond to those interruptions. Ineffective security measures at best allow us to blame the victim, particularly when the fault lies not with the victim but with insecure system designs.
Misty takes a different approach. Instead of attempting to add security, it makes it possible to remove sources of insecurity. It does this by giving each actor or function in an application system just the resources it needs in order to do its work and no more. The potential amount of intentional or unintentional mischief is substantially reduced. It is as if there is a firewall around every single object in the application. Misty does this while introducing no additional run-time overhead.
Misty is able to do this because it is an Object-Capability System. Secrets and powerful actions can be hidden behind objects that will properly control access. This is object-oriented security.
In an Object-Capability System, there are exactly three ways in which to obtain an object reference:
No other means are possible. References cannot be obtained by simply
knowing the name of something (such as 'root'
), or by pointer-arithmetic,
or from global variables or public class variables. With this level of
object containment, if two pieces of hostile code are loaded in the same
actor, they will not be able to call each other or exchange object references
without there first being an introduction.
With such containment, object references become tokens of authority. If a function has a reference to an object, then it has the authority to interact with that object.
stone
The stone
function makes an object immutable. Stone objects can be passed to malicious functions without risk of tampering.
The stone
function has no effect on values that are already
immutable.
Record references should always be stoned before they are passed through a trust boundary. A stoned record allows read-only access to its data members, and invocation of its functions.
Getting a value from an object or setting a value on an object never causes a transfer of control except when panic occurs
Functions are first class immutable values and can be stored in and retrieved from objects.
Misty functions are lambdas. They bind context with a specific set of parameters and statements. This binding (or closure) provides mechanisms for creating private variables. Functions only have access to the values they are bound to.
A facet is an object or function that acts as an intermediary. A facet can provide a limited interface to a more powerful object or function. A facet can filter, check, and validate requests. For example, a file system facet might permit access to only certain directories, or prevent files from growing beyond a certain size. The facet object looks to the application like a file system object, but the operations it permits are limited.
Facets can also be used to provide revocability. A facet can be ordered by its issuer to become inert, which effectively prevents the application from making further use of it. A facet can also be constructed to work only once and then become inert.
Records can use other records as property keys. Since records are capabilities, latent properties can be accessed only when holding both the record and the key.
def latent: {} # hold the undiscoverable key my_record[latent] # using the key
In the above example, my_record
and latent
are both capabilities. The secret content can only be obtained by holding both of them.
Actors are made of functions and benefit from the security properties of those functions. Each actor is an independent process. A process does not share any memory with other processes, so corruption of one process has no impact on the other processes.
Every actor has a private address. The only way to interact with an actor is by sending a message to the private address. If you do not have a private address, you can not send a message. An actor's private address is a capability.
There are situations where code representing another party is allowed to run in your system alongside your own code. Web browsers do this. This situation has obvious security problems.
Misty can mitigate the problems. First, the code that the guest is to run is delivered to the misty system in source form. The code is compiled with the most restrictive policies. The executable is placed in the program shopwith a distinctive name.
When a guest program is launched with @.new()
, the guest program can be given a very restricted with of capabilities.
It will not be able to create other actors. It will only be able to send messages to its home system. It will not have an @.portal()
function. It will not have an @.garbage()
function. Instead, when it becomes unreachable, it automatically dies. It will only have the capabilities that it is explicitly given, so its opportunities to commit mischief are drastically constrained. However, it will be able to do things that are mutually beneficial.
The security of the Misty language depends on the security of the run-time environment. The interfaces that are provided should practice Capability Discipline.
The Misty System does not depend on passwords, certificates, permission tables, or access control lists. It instead relies on object references, which are unforgable, and actor addresses, which are unguessable and cryptographically protected, and public/private keys.