4 ms·
The brilliant thing about capability-based security is that it turns classic object-oriented programming patterns into security patterns. Access control is imp
by kentonv 11y ago
The brilliant thing about capability-based security is that it turns classic object-oriented programming patterns into security patterns.
Access control is implemented by encapsulating private members behind a restricted public interface.
Polymorphism allows you to add wrappers around an object implementing arbitrary security policies. E.g. want to revoke access to this object after some time? Add a wrapper where the methods forward to the real object until revoked, and then throw exceptions instead.
What's interesting is that these are patterns we are doing anyway, in real code, not for the purpose of security but for the purpose of correctness and maintainability. Because we were doing these things anyway, our programming languages provide really good tools for making them work naturally, and we already know how to think about them.
On the other hand, the competing model -- access control lists (ACLs), and other types of externally-specified policy -- are not things we were doing anyway. They're external concepts bolted into the system awkwardly. Because of this, they tend to be painful to maintain, which in turn means people often don't bother.
One of the clearest examples of how ACLs go against the grain: An ACL is a list of entities who are allowed to access a resource. These are effectively pointers pointing in the opposite direction of all other pointers in the system: ACLs point from the callee to the caller. This creates all kinds of problem. Just try to imagine how, in a programming language, you would specify the allowed callers of your object.
This translates to UX, too: Say you are using Google Docs, and you want to "share" access to a document with Alice. Traditionally this is seen (by the implementers -- I was once on the Google Docs sharing team) as a two-step process:
1. Grant access: Add Alice to the access control list.
2. Notify: Send Alice an e-mail notifying her that she should open the document.
Part 2 is obviously necessary and natural. You intuitively know you must tell Alice about your document.
Part 1 may sound obvious to any techie, but it's not at all: Users regularly forget this step, and we build all kinds of UI to try to recover from this. And even if it were obvious, it's problematic. What if Alice doesn't have a Google account? What if she does, but I don't know the email address tied to that account, because it's not her usual address?
What we really want to do is eliminate part 1 and have only part 2: Abstractly, when you notify Alice of the document, that notification should itself contain the permission to access the document. Then I don't need to know Alice's Google account ID, I just need to know how to send her a message containing the permissions. (This is analogous to sending a pointer in code -- receiving the pointer grants the recipient the ability to access the pointed-to object.)
This is the essence of capability-based security at the UX level: Deriving access control from actions you were already doing. The user rarely needs to be confronted with a security action, yet the right people end up getting access.
Some will argue that such implicit security is inherently dangerous because it's hard to audit and control. I argue that "explicit" security is dangerous because it's hard for users to understand and use correctly -- inevitably, many will simply turn the security off.
But there's a compromise: If the underlying system deeply understands capabilities and knows when they are being passed, it can maintain an "access control list" on the side, automatically populating it based on the observed movement of capabilities. This pseudo-ACL can allow the user to audit who has access to their document and revoke people who shouldn't be there. It also offers a place to hook in policies: if the system observes a capability movement that is contrary to some explicit policy (say, "documents shall not be shared outside the organization"), then it can revoke that capability.
This is the model we're implementing in Sandstorm:
https://sandstorm.io https://sandstorm.io
https://docs.sandstorm.io/en/latest/developing/security-practices/ https://docs.sandstorm.io/en/latest/developing/security-prac...
And Cap'n Proto RPC implement capabilities at the network level:
https://capnproto.org/rpc.html https://capnproto.org/rpc.html
(I am the lead developer of both Sandstorm and Cap'n Proto.)
Other good reading:
http://srl.cs.jhu.edu/pubs/SRL2003-02.pdf http://srl.cs.jhu.edu/pubs/SRL2003-02.pdf - Capability Myths Demolished, an academic paper.
http://joeduffyblog.com/2015/11/10/objects-as-secure-capabilities/ http://joeduffyblog.com/2015/11/10/objects-as-secure-capabil... - About Microsoft's Midori research OS, which was also based on this model.
- stolsvik 11y agoIsn't the second approach a bit like when you send a special link to access the document? Which leads to the obvious "Anyone with the link can access the document"-ness with that solution? How do you avoid that situation - that if the link spreads, you effectively lose control until you realize and remove the link-based access of the document?
- Natanael_L 11y agoThe link might as well be the document itself, a proxy into the computer of the person you shared it to. That's the point of capabilities. And that's why you want them to be revocable. You can make it a bit simpler by having the permission be a one time only token for requesting account specific permissions too. Works if you know how many people the link needs to be shared with (and ideally if you can give them separate links). But fails your goal if the link must be reused.
- noblethrasher 11y agoOne of the maxims of capability-based security is: “don't prohibit what you can't prevent”. If I give Alice a capability, I can no more prevent her from sharing it with Eve than I can prevent her from being a proxy for Eve. This makes capabilities a more honest form of systems security.
- kentonv 11y agoSecret URLs ("anyone with the link can access") are a weak form of capabilities. They are problematic since they can't be traced nor revoked. A good capability system allows you to audit where the capability has gone and revoke it from specific parties without revoking it from everybody. A good capability system also makes capabilities harder to "leak" accidentally, while still allowing them to be transferred intentionally. For an example of capabilities that can't leak, look at Unix file descriptors. A process can transfer a file descriptor to another process via an SCM_RIGHTS message over a unix domain socket. The receiving process is able to perform exactly the same set of operations on the file descriptor as the sending process could, even if the receiving process belongs to a different user who doesn't have permission to open() the underlying file. Thus the FD is like a capability. File descriptors are not secret tokens -- they are easily-guessable small integers. But they cannot accidentally "leak" between processes because the OS explicitly involved in all transfers. (Of course, file descriptors still lack traceability and revocability, which a good capability system should support.)