[Python-Dev] Re: Capabilities (original) (raw)

Zooko zooko@zooko.com
Mon, 10 Mar 2003 16:15:18 -0500


(I, Zooko, wrote the lines prepended with "> > ".)

Guido wrote:

> The [Principle-of-Least-Privilege approach to securing a standard library] > is to separate the tools so that dangerous ones don't come tied together > with common ones. The security policy, then, is expressed by code that > grants or withholds capabilities (== references) rather than by code that > toggles the "restricted" bit. This sounds interesting, but I'm not sure I follow it. Can you elaborate by giving a couple of examples?

First let me say that "capability access control" [1] is a theoretical construct, comparable to "access control lists" [2] and "Trust Management" [3]. Each is a formal model for specifying access control rules -- who is allowed to do what.

But in the context of Python we are interested not only in the theoretical model but also in a specific way of implementing it -- by making object references unforgeable and binding all authorities to object references.

So in this discussion it may not be clear whether a claimed advantage of "capabilities" flows from the formal model or from the practice of unifying security programming with object oriented programming. I don't think it is important to differentiate in this discussion.

Now for examples...

Hm, well first of all, where are rexec and Zope proxies currently used?
I believe that a "cap-Python" would support those uses, implementing the same security policies, but more cleanly since access control would be a first-class part of the language.

I don't know Zope very well, and rather than guess, I'd like to ask someone who does know Zope to give a typical example of how proxies are used in workaday Zope. I suspect that capabilities are quite similar to Zope proxies.

Now for a quick made-up example to demonstrate what I meant about expressing security policy above, consider a tic-tac-toe game that is supposed to draw to the screen.

In "restricted Python v1", certain modules have been flagged as "safe" and others "unsafe". Code can execute other code with a "restricted" flag set, something like this:

restricted Python v1

game = eval(TicTacToeGame, restricted=True) game.display()

Unfortunately, in "restricted Python v1", all of the modules that allow drawing to the screen are marked as "unsafe", so the tic-tac-toe-game immediately dies with an exception.

In "restricted Python v2", an arbitrary security policy can be implemented:

restricted Python v2

games=[] def securitypolicy(subject, action, object): if ((subject in games) and (action == "import") and (object == "wxPython")) or (subject in games) and (action == "execute") and (object == "wxPython.Window") or (subject in games) and (action == "execute") and (object == "wxPython.Window.paint")): return True # ... return False

game = eval(TicTacToeGame, policy=securitypolicy) gameobjh.append(game) game.display()

I think that the "rexec" design was along the lines of "restricted Python v2", but I apologize if this simple analogy insults anyone.

I'm not sure whether "restricted Python v2" is expressive enough to implement the capability security access control model or not, but I don't care, because I don't like "restricted Python v2". I like restricted Python v3:

restricted Python v3

game = TicTacToeGame() game.display(wxPython.wxWindow())

Now the game object has a reference to the window object, and it can use that reference to draw the pictures. If I later change this design and decide that instead of drawing to a window, I want the game to write to a file, then I'll change the implementation of the TicTacToeGame class, and then'll I'll come back here to this code and change it from passing a wxWindows to:

restricted Python v3

game = TicTacToeGame() game.display(open("/tmp/tttgame.out","w"))

Now if I were writing in "restricted Python v2", then in addition to those two changes I would also have to make a third change, which is to edit my securitypolicy function in order to allow this particular game object to access a file named "/tmp/tttgame.out", and to disallow it access to wxPython:

restricted Python v2

def securitypolicy(subject, action, object): if (subject in games) and (action in ("read", "write",)) and (object == "file:/tmp/tttgame.out"): return True # ... return False

game = TicTacToeGame() game.display("/tmp/tttgame.out")

This is what I meant by saying that the security policy is expressed in Python instead of by twiddling access bits in an embedded policy language. In a capability-secure language, the change (which the programmer has to make anyway), from "wxPython.wxWindows()" to "open('/tmp/tttgame.out', 'w')" is necessary and sufficient to enforce the programmer's intended security policy, so there is no need for the redundant and brittle "policy" function.

I find this unification access control and application logic to resonate deeply with the Zen of Python.

Regards,

Zooko

[1] http://www.eros-os.org/papers/shap-thesis.ps [2] http://www.research.microsoft.com/~lampson/09-Protection/Acrobat.pdf [3] http://citeseer.nj.nec.com/blaze96decentralized.html