8

我有一个问题,我选择 Python 作为更大项目的可能语言的决定取决于答案——我自己想不出:

我们都知道 Python 没有真正的对象封装,所以没有什么像对象的“私有”属性。关于这个问题,Guido van Rossum 说,一个人可以在不被“允许”的情况下访问异物的隐藏部分,“我们都是成年人”,“只是不要这样做”。只要我写的软件在我自己的手中,我就可以过得很好,所以我要为自己的错误负责,并且可以尽量避免这样的事情。

但是 - 我的问题来了:如果我提供一个插件框架,其中包含一些具有一些扩展点的插件,并且许多插件是由其他人提供的,也许是我不能完全信任的人。

如何防止暴露我的框架内部被插件访问?

有没有办法实现这一点,或者是使用 Python 确信没有人会滥用我的 API 的唯一方法?

4

1 回答 1

18

您永远不应该真正依赖private, publicetc 来确保安全(如“防止恶意代码和外部威胁”)。它们的目的是防止程序员在脚下开枪,而不是作为(计算机)安全措施。您也可以轻松访问 C++ 对象的私有成员字段,只要您绕过静态编译器检查并直接进入内存,但您会说 C++ 缺乏真正的封装吗?

因此,您永远不会真正使用privateprotected作为针对 C++ 或 Java 中的恶意插件的安全措施,我也假设 C# 也是如此。

您最好的选择是在单独的进程中运行您的插件,并通过 IPC/RPC 甚至 Web 服务公开核心 API,或者在沙箱中运行它们(正如 @MarkHildreth 指出的那样)。或者,您可以为您的插件设置认证和签名流程,以便您可以在潜在的恶意插件分发之前对其进行审查和过滤。

笔记:

您实际上可以使用词法闭包实现真正的封装:

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

...但即便如此,该值实际上仍然可以通过反射相对容易地访问:

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

...即使这是不可能的,我们仍然可以ctypes允许直接访问内存,绕过任何剩余的装饰性“限制”:

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

现在您可以分配给arr它或从中读取;尽管您必须努力将指针从那里遍历到存储的实际内存位置.param,但这证明了这一点。

于 2013-10-02T19:39:33.660 回答