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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1350466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 22:01:55  来源:igfitidea点击:

Preventing Python code from importing certain modules?

pythonmodulesandbox

提问by del-boy

I'm writing an application where users can enter a python script and execute it in a sandbox. I need a way to prevent the exec'ed code from importing certain modules, so malicious code won't be as much of a problem. Is there a way to do this in Python?

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

回答by del-boy

If you put None in sys.modules for a module name, in won't be importable...

如果您在 sys.modules 中为模块名称设置 None ,则将无法导入...

>>> 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
>>>

回答by nilamo

Have you checked the python.org article on SandboxedPython, and the linked article?

您是否检查过有关 SandboxedPython 的 python.org文章链接的文章

Both of those pages have links to other resources.

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

Specifically, PyPi's RestrictedPythonlets you define exactly what is available, and has a few 'safe' defaults to choose from.

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

回答by Alex Martelli

Google App Engine's open source SDKhas a detailed and solid implementation of mechanics to stop the importing of unwanted modules (to help detect code trying to import modules that aren't made available in the production instances of App Engine), though even that could be subverted if the user code was evil rather than just mistaken (production instances obviously have more layers of defense, such as simply not having those modules around at all;-).

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

So it all depends on how in-depth your defense needs to be. At one extreme you just stash the builtin __import__somewhere else and replace it with your function that does all the checks you want before delegating to the __builtin__; that's maybe 20 lines of code, 30 minutes to implement and test thoroughly... but it might not protect you for long if somebody credibly offered mea million bucks to break into your system (and, hypothetically, I wasn't the goody-two-shoes kind of guy I actually AM, of course;-). At the other extreme you deploy an in-depth series of layers of defense that might take thousands of lines and weeks of implementation and testing work -- given that kind of resource budget I could surely implement something Iwould be unable to penetrate (but there's always the risk that somebody ELSE is smarter and more Python-savvy than I am, of course!).

所以这完全取决于你的防御需要有多深入。在一种极端情况下,您只需将内置__import__函数存放在其他地方,然后用您的函数替换它,该函数在委托给__builtin__;之前执行您想要的所有检查。这可能是 20 行代码,需要 30 分钟来彻底实施和测试……但如果有人可靠地向提供一百万美元来闯入你的系统,它可能无法保护你很长时间(而且,假设,我不是那个好人——当然,我实际上是那种穿两双鞋的人;-)。在另一个极端部署进行了深入的一系列防御层,可能需要上千行和执行周和测试工作-因为那种资源预算的我肯定可以实现的东西将无法渗透(但总有这样的风险,即 ELSE 比我更聪明,更精通 Python,当然!)。

So, how deep do you want to go, or rather, how deep can you AFFORD to go...?

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

回答by Tcll

8 years, yeesh, and nobody has figured this one out? :/

8 年了,是的,没有人弄清楚这一点?:/

You can override the importstatement or aka the __import__function.

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

This is just a tested scribble-code because I couldn't find any legit reference:

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

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

and here's the tests for that code:

这是该代码的测试:

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
>>> 

Please do not comment about me using Python34, I have my reasons, and it's my primary interpreter on Linux specifically for testing things (like the above code) for my primary project.

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

回答by Martin Beckett

You can overload the import mechanism. We used this to have a licensing system for plugins, you can easily have a whitelist / blacklist of module names.

您可以重载导入机制。我们使用它来为插件提供许可系统,您可以轻松拥有模块名称的白名单/黑名单。

回答by EMP

Unfortunately, I think that what you're trying to do is fundamentally impossible. If users can execute arbitrary code in your application then they can do whatever they want. Even if you were able to prevent them from importing certain modules there would be nothing stopping them from writing equivalent functionality themselves (from scratch or using some of the modules that are available).

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

I don't really know the specifics of implementing a sandbox in Python, but I would imagine it's something that needs to be done at the interpreter level and is far from easy!

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