Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python object encapsulation security

I have a question, and my decision in choosing Python as a possible language for a bigger project depends on the answer - which I cannot come up with myself:

We all know that Python has no real object encapsulation, so there is nothing like "private" properties of an object. Regarding this issue, Guido van Rossum says that one can access hidden parts of a foreign object without being "allowed" to, with "we are all adults", "just don't do it". I can live perfectly well with that, as long as the software I write is in my own hand, so I am responsible for my own errors and just can try to avoid such things.

BUT - and here comes my question: What if I provide a plugin framework with some plugins that have some extension points, and many of the plugins are by OTHER people, maybe ones that I cannot trust completely.

How do I prevent exposing internals of my framework from being accessed by a plugin?

Is there a way to achieve this, or is the only way to use Python having confidence that no one will abuse my API?

like image 575
nerdoc Avatar asked Oct 02 '13 19:10

nerdoc


People also ask

What is encapsulation in OOP Python?

Encapsulation is a mechanism of wrapping the data (variables) and code acting on the data (methods) together as a single unit. In encapsulation, the variables of a class will be hidden from other classes, and can be accessed only through the methods of their current class.

Is encapsulation possible in Python?

In Python, Encapsulation can be achieved by declaring the data members of a class either as private or protected. In Python, 'Private' and 'Protected' are called Access Modifiers, as they modify the access of variables or methods defined in a class.

How does encapsulation work in Python explain it with an example?

Encapsulation in Python describes the concept of bundling data and methods within a single unit. So, for example, when you create a class, it means you are implementing encapsulation. A class is an example of encapsulation as it binds all the data members (instance variables) and methods into a single unit.

Is Python object oriented?

Python is an object oriented programming language. Almost everything in Python is an object, with its properties and methods. A Class is like an object constructor, or a "blueprint" for creating objects.


1 Answers

You should never really rely on private, public etc for security (as in "protection against malicious code and external threats"). They are meant as something to keep the programmer from shooting himself in the foot, not as a (computer) security measure. You can also easily access private member fields of C++ objects, as long as you bypass static compiler checks and go straight to the memory, but would you say that C++ lacks true encapsulation?

  • For C++, see http://phoxis.org/2012/01/25/accessing-private-data-members-directly-outside-from-its-class-in-c/
  • Same about the JVM (and thus Java): How do I read a private field in Java?
  • And (more or less) the same about CLR (i.e. .NET): Does reflection breaks the idea of private methods, because private methods can be access outside of the class?

So you would never really use private or protected as a security measure against malicious plugins in C++ nor Java, and I assume C# as well.

Your best bet is to run your plugins in a separate process and expose the core API over IPC/RPC or even web service, or run them in a sandbox (as per what @MarkHildreth pointed out). Alternatively, you can set up a certification and signing process for your plugins so that you can review and filter out potentially malicious plugins before they even get distributed.

NOTE:

You can actually achieve true encapsulation using lexical closures:

def Foo(param):
    param = [param]  # because `nonlocal` was introduced only in 3.x
    class _Foo(object):
        @property
        def param(self):
            return param[0]
        @param.setter
        def param(self, val):
            param[0] = val
    return _Foo()

foo = Foo('bar')
print foo.param  # bar
foo.param = 'baz'
print foo.param  # baz
# no way to access `foo._param` or anything

...but even then, the value is actually still relatively easily accessible via reflection:

>>> foo.__class__.param.fget.__closure__[0].cell_contents[0] = 'hey'
>>> foo.param
'hey'

...and even if this weren't possible, we'd still be left with ctypes which allows direct memory access, bypassing any remaining cosmetic "restrictions":

import ctypes
arr = (ctypes.c_ubyte * 64).from_address(id(foo))

and now you can just assign to arr or read from it; although you'd have to work hard to traverse pointers from there down to the actual memory location where .param is stored, but it proves the point.

like image 146
Erik Kaplun Avatar answered Oct 02 '22 14:10

Erik Kaplun