[Python-Dev] Security capabilities in Python

Jp Calderone exarkun at divmod.com
Sat Apr 9 11:02:23 CEST 2005


On Sat, 9 Apr 2005 00:13:40 -0500 (CDT), Ka-Ping Yee <python-dev at zesty.ca> wrote:
>On Fri, 8 Apr 2005, Eyal Lotem wrote:
> > I would like to experiment with security based on Python references as
> > security capabilities.
> 
> This is an interesting and worthwhile thought.  Several people
> (including myself) have talked about the possibility of doing
> this in the past.  I believe the two problems you mention can be
> addressed without modifying the Python core.
> 
> > * There is no way to create secure proxies because there are no
> > private attributes.
> 
> Attributes are not private, but local variables are.  If you use
> lexical scoping to restrict variable access (as one would in
> Scheme, E, etc.) you can create secure proxies.  See below.
> 
> > * Lots of Python objects are reachable unnecessarily breaking the
> > principle of least privelege (i.e: object.__subclasses__() etc.)
> 
> True.  However, Python's restricted execution mode prevents access
> to these attributes, allowing you to enforce encapsulation.  (At
> least, that is part of the intent of restricted execution mode,
> though currently we do not make official guarantees about it.)
> Replacing __builtins__ activates restricted execution mode.
> 
> Here is a simple facet function.
> 
>     def facet(target, allowed_attrs):
>         class Facet:
>             def __repr__(self):
>                 return '<Facet %r on %r>' % (allowed_attrs, target)
>             def __getattr__(self, name):
>                 if name in allowed_attrs:
>                     return getattr(target, name)
>                 raise NameError(name)
>         return Facet()
> 
>     def restrict():
>         global __builtins__
>         __builtins__ = __builtins__.__dict__.copy()
> 
>     # Here's an example.
> 
>     list = [1, 2, 3]
>     immutable_facet = facet(list, ['__getitem__', '__len__', '__iter__'])
> 
>     # Here's another example.
> 
>     class Counter:
>         def __init__(self):
>             self.n = 0
> 
>         def increment(self):
>             self.n += 1
> 
>         def value(self):
>             return self.n
> 
>     counter = Counter()
>     readonly_facet = facet(counter, ['value'])
> 
> If i've done this correctly, it should be impossible to alter the
> contents of the list or the counter, given only the immutable_facet
> or the readonly_facet, after restrict() has been called.
> 
> (Try it out and let me know if you can poke holes in it...)
> 
> The upshot of all this is that i think you can do secure programming
> in Python if you just use a different style.  Unfortunately, this
> style is incompatible with the way classes are usually written in
> Python, which means you can't safely use much of the standard library,
> but i believe the language itself is not fatally flawed.
> 

  Does using the gc module to bypass this security count?  If so:

    exarkun at boson:~$ python -i facet.py 
    >>> import gc
    >>> c = readonly_facet.__getattr__.func_closure[1]
    >>> r = gc.get_referents(c)[0]
    >>> r.n = 'hax0r3d'
    >>> readonly_facet.value()
    'hax0r3d'
    >>> 

  This is the easiest way of which I know to bypass the use of cells as a security mechanism.  I believe there are other more involved (and fragile, probably) ways, though.

  Jp


More information about the Python-Dev mailing list