[Python-Dev] Capabilities

Jim Fulton jim@zope.com
Mon, 10 Mar 2003 07:23:08 -0500


Ka-Ping Yee wrote:
> Ben Laurie wrote:
> 
>>BTW, if you would like to explain why you don't think bound methods are
>>the way to go on python-dev, I'd love to hear it.
> 
> 
> Guido van Rossum wrote:
> 
>>Using capabilities, I would have to hand her
>>a bunch of capabilities for various methods: __getitem__, has_key,
>>get, keys, items, values, and many more.  Using proxies I can simply
>>give her a read-only proxy for the object.  So proxies are more
>>powerful.

I'm pretty sure that Guido meant to say "bound method" rather than
"capability" in the text above.  I think that the debate is partly
whether to express capabilities (or some other scheme) in terms of
bound methods or proxies, which expose entire interfaces.

> There seems to be a persistent confusion here that i would like
> to dispel: a capability is not a single lambda.

There are a bunch of confusions floating around. :)
A major one is a concise definition os what a capability and
why the capability approach is good or bad.

In reading about capabilities in E, http://www.erights.org/.
I really need to read all that stuff again.  Of course,
as others pointed out, I ended up creating something for Zope 3
that isn't capabilities.  I think you touch on a reason below.



> Guido's paragraph, above, seems to believe that it is.  In fact,
> the pattern he described is a common and powerful way of using
> capabilities.  A capability is just an unforgeable object reference.
> In a pure capability system, the only thing you can do with a
> capability is to call methods on it (or, if you prefer, all you
> can do is send messages to it).  Interposing an object to expose
> only a subset of another object's API, such as a read-only subset,
> is exactly the power capabilities give you.
> 
> It seems to me that the "rexec vs. proxy" debate is really about
> a very different question: How do we get from Python's currently
> promiscuous objects to properly restricted objects?
> 
> (Once we have properly restricted objects in either fashion, yes,
> definitely, using proxies to restrict access is a great technique.)
> 
> If i understand correctly, the "proxy" answer is "we create a
> special wrapper object, then the programmer has to individually
> wrap any object they want to be secure".  And the "rexec" answer
> is "we create an interpreter mode in which all objects are secure".
> 
> I think the latter is far better.  To have any sort of real chance
> at establishing security, you have to start from a place where
> everything is secure, instead of starting from a place where
> everything is insecure and you have to individually secure every
> single object with its own wrapper.
 >
> The eventual ideal is to have a system where all objects are
> "pure" objects (i.e. non-introspectable capabilities) by default.
> Anyone wanting to do introspection would simply have to obtain
> the "introspect" capability from a privileged place (e.g. sys).
> For example,
> 
>     class Foo:
>         pass
> 
>     print Foo.__dict__                  # fails
> 
>     from sys import introspect
>     print introspect(Foo).__dict__      # succeeds
> 
> When running the interpreter in secure mode, "introspect"
> would just be missing from the sys module (again, ideally
> sys.introspect wouldn't exist by default, and a command-line
> option would turn it on, but i realize that's far away).
> 
> This would have the effect of the "introspectable flag" that
> Guido mentioned, but without expending any storage at all,
> until you actually needed to introspect something.

You seem to be arguing that programmers should not have to
explictly create capabilities, but that everythink should be a capability
by default.  Please correct me if I'm wrong.

I thought that the main point of capabilities was that programmers
*should* explictly bother to pass capabilities.  Programmers should
think about arguments passed to (or returned or raised to) other code as
capabilities to do things and pass *just* the capabilities needed.
I find a lot of appeal in this idea.

Zope employs proxies in a way that falls somewhere between the extremes of
capabilities and implicitly protecting everything.

(I'm going to be a little sloppy hear for brevity. A Zope proxy is made up
of two objects, a simple proxy that *could* be used to implement capabilities
and a checker that provides policy. The policy we currently use in Zope is
not a capability policy.)

Zope security proxies assure that "everything" is proxied. (We choose not
to proxy simple valies like numbers, strings, and None.) Values returned
from operations on proxied. This maked it pretty straightforward to set up
execution environments where untrusted code only has access to proxies. In addition,
if untrusted code calls trusted code, the untrusted code can only pass proxies.
This means that trusted code can't be tricked into performing operations that
the untrusted code could not perform.  Zope proxies achiev this level of automation
by providing registries, mostly based on classes, that allow programmers to say
how different kinds of objects should be proxied. Programmers decide what capabilities
to expose at "compile" time (really program startup) rather than run time.
Programmers *can* create proxies explicitly that provides non-default access.
In fact, there are apis that actually provide the the equivalent of capabilities.

I mention all of this because I think it's worth thinking/debating this issue
about how explicit security should be. On the one hand, explictly giving *just*
the capabilities needed for a task seems very appealing. OTOH, making sure
that everything is protected by default is safer.  I suspect that there
are ways to combine (trade off?) these in reasonable ways.

Jim

-- 
Jim Fulton           mailto:jim@zope.com       Python Powered!
CTO                  (888) 344-4332            http://www.python.org
Zope Corporation     http://www.zope.com       http://www.zope.org