防止Python代码导入某些模块?

时间:2009-08-29 04:39:33

标签: python module sandbox

我正在编写一个应用程序,用户可以在其中输入python脚本并在沙箱中执行它。我需要一种方法来防止exec的代码导入某些模块,因此恶意代码不会成为一个问题。有没有办法在Python中执行此操作?

7 个答案:

答案 0 :(得分:22)

如果在sys.modules中为模块名称添加None,则in将无法导入...

>>> import sys
>>> import os
>>> del os
>>> sys.modules['os']=None
>>> import os
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named os
>>>

答案 1 :(得分:16)

你检查了python.org article on SandboxedPythonlinked article吗?

这两个页​​面都有其他资源的链接。

具体来说,PyPi的RestrictedPython允许您准确定义可用的内容,并且有一些“安全”默认值可供选择。

答案 2 :(得分:7)

Google App Engine的开源SDK具有详细而可靠的机制实现,可以停止导入不需要的模块(以帮助检测尝试导入App Engine生产实例中未提供的模块的代码),如果用户代码是邪恶而不是错误的话,即使这可能被颠覆(生产实例显然有更多的防御层,例如根本没有这些模块; - )。

所以这一切都取决于你的防守需要多深入。在一个极端,您只需将内置__import__存储在其他地方,并将其替换为您的功能,该功能在委派给__builtin__之前执行您想要的所有检查;这可能是20行代码,30分钟实现并彻底测试......但是如果有人可靠地提供一百万美元来闯入你的系统,它可能无法长时间保护你(假设,当然,我不是那种我真正上午的两个男人! - )。在另一个极端,你部署了一系列深层防御层,可能需要数千行和几周的实施和测试工作 - 鉴于这种资源预算,我肯定可以实现 I 无法穿透(但总有一种风险,那就是ELSE比我更聪明,更精通Python!)。

那么,你想要去多深,或者更确切地说,你有多深才能去......?

答案 3 :(得分:5)

8年,是的,没有人认出这个? :/

您可以覆盖import语句或__import__函数。

这只是一个经过测试的涂鸦代码,因为我找不到任何合法的参考资料:

import importlib

def secure_importer(name, globals=None, locals=None, fromlist=(), level=0):

    if name != 'C': print(name, fromlist, level)

    # not exactly a good verification layer
    frommodule = globals['__name__'] if globals else None
    if name == 'B' and frommodule != 'C':
        raise ImportError("module '%s' is restricted."%name)

    return importlib.__import__(name, globals, locals, fromlist, level)

__builtins__.__dict__['__import__'] = secure_importer

import C

以下是该代码的测试:

Python 3.4.3 |Anaconda 2.3.0 (32-bit)| (default, Mar  6 2015, 12:08:17) [MSC v.1600 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
B ('f',) 0
imported secure module
>>> from B import f
B ('f',) 0
linecache None 0
encodings.utf_8 ['*'] 0
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    from B import f
  File "\home\tcll\Projects\python\test\restricted imports\main.py", line 11, in secure_importer
    raise ImportError("module '%s' is restricted."%name)
ImportError: module 'B' is restricted.
>>> import C
>>> 

请不要使用Python34对我发表评论,我有我的理由,这是我在Linux上的主要解释器,专门用于测试我的主要项目的内容(如上面的代码)。

答案 4 :(得分:1)

不幸的是,我认为你想要做的事情根本不可能。如果用户可以在您的应用程序中执行任意代码,那么他们可以随心所欲。即使您能够阻止它们导入某些模块,也没有什么能阻止它们自己编写等效的功能(从头开始或使用一些可用的模块)。

我真的不知道在Python中实现沙箱的具体细节,但我认为这需要在解释器级别完成并且远非易事!

答案 5 :(得分:0)

您可以重载导入机制。我们使用它来设置插件许可系统,您可以轻松获得模块名称的白名单/黑名单。

答案 6 :(得分:0)

您可以将自定义MetaPathFinder注册为sys.meta_path的第一个元素。该查找程序可以维护模块的白名单,如果可以接受导入,则返回None,以便委托给其他查找程序,如果导入不合法,则引发ImportError

from importlib.abc import MetaPathFinder
import sys


class Whitelist(MetaPathFinder):
    def __init__(self, whitelist):
        super().__init__()
        self.whitelist = whitelist

    def find_spec(self, fullname, path, target=None):
        if fullname not in self.whitelist:
            raise ImportError(fullname)


sys.meta_path.insert(0, Whitelist({'math'}))

import math  # works
import typing  # raises ImportError

但是,在解释器启动时,已经自动导入了一堆模块。您可以使用-v标志(例如, python -vc ""(这是一长串,所以我不会在这里复制它。)

因此,您还需要从sys.modulessys.modules.clear()中清除这些模块。