简体   繁体   English

禁用嵌入式Python中的内置模块导入

[英]Disable built-in module import in embedded Python

I'm embedding Python 3.6 in my application, and I want to disable import command in the scripts to prevent users to import any python built-in libraries. 我在我的应用程序中嵌入了Python 3.6,我想在脚本中禁用import命令以防止用户导入任何python内置库。 I'd like to use only the language itself and my own C++ defined modules. 我只想使用语言本身和我自己的C ++定义模块。

Py_SetProgramName (L"Example");
Py_Initialize ();
PyObject* mainModule = PyImport_AddModule ("__main__");
PyObject* globals = PyModule_GetDict (mainModule);

// This should work
std::string script1 = "print ('example')";
PyRun_String (script1.c_str (), Py_file_input, globals, nullptr);

// This should not work
std::string script2 = "import random\n"
                      "print (random.randint (1, 10))\n";
PyRun_String (script2.c_str (), Py_file_input, globals, nullptr);

Py_Finalize ();

Do you know any way to achieve this? 你知道怎么做到这一点吗?

Python has a long history of being impossible to create a secure sandbox (see How can I sandbox Python in pure Python? as a starting point, then dive into an old python-dev discussion if you feel like it). Python有很长的历史,无法创建一个安全的沙箱(请参阅我如何在纯Python中沙盒Python?作为起点,然后深入探讨旧的python-dev讨论,如果您愿意的话)。 Here are what I consider to be your best two options. 以下是我认为最好的两种选择。

Pre-scan the code 预扫描代码

Before executing anything, scan the code. 在执行任何操作之前,请扫描代码。 You could do this in Python with the AST module and then walk the tree, or can likely get far enough with simpler text searches. 您可以使用AST模块在Python中执行此操作,然后遍历树,或者可以通过更简单的文本搜索获得足够的效果。 This likely works in your scenario because you have restricted use cases - it doesn't generalize to truly arbitrary code. 这可能适用于您的场景,因为您具有受限的用例 - 它不会推广到真正任意的代码。

What you are looking for in your case will be any import statements (easy), and any top-level variables (eg, in abc you care about a and likely ab for a given a ) that are not "approved". 在您的情况下,您正在寻找的是任何import语句(简单),以及任何顶级变量(例如,在abc您关心某个给定a a和可能的ab )并非“已批准”。 This will enable you to fail on any code that isn't clean before running it. 这将使您在运行之前对任何不干净的代码失败。

The challenge here is that even trivally obfuscated code will bypass your checks. 这里的挑战是即使是模糊的代码也会绕过你的检查。 For example, here are some ways to import modules given other modules or globals that a basic scan for import won't find. 例如,以下是一些导入模块的方法,这些模块给定了import的基本扫描找不到的其他模块或全局变量。 You would likely want to restrict direct access to __builtins__ , globals , some/most/all names with __double_underscores__ and members of certain types. 您可能希望使用__double_underscores__和某些类型的成员限制对__builtins__ __double_underscores__globals ,某些/大多数/所有名称的直接访问。 In an AST, these will unavoidably show up as top-level variable reads or attribute accesses. 在AST中,这些将不可避免地显示为顶级变量读取或属性访问。

getattr(__builtins__, '__imp'+'ort__')('other_module')

globals()['__imp'+'ort__']('other_module')

module.__loader__.__class__(
    "other_module",
    module.__loader__.path + '/../other_module.py'
).load_module()

(I hope it goes somewhat without saying, this is an impossible challenge, and why this approach to sandboxing has never fully succeeded. But it may be good enough, depending on your specific threat model.) (我希望有点不用说,这是一个不可能的挑战,为什么这种沙盒方法从未完全成功。但它可能已经足够好了,具体取决于您的特定威胁模型。)

Runtime auditing 运行时审核

If you are in a position to compile your own Python runtime, you might consider using the (currently draft) PEP 551 hooks. 如果您可以编译自己的Python运行时,可以考虑使用(当前草案) PEP 551钩子。 (Disclaimer: I am the author of this PEP.) There are draft implementations against the latest 3.7 and 3.6 releases. (免责声明:我是本PEP的作者。)针对最新的3.73.6版本提供了草案实施。

In essence, this would let you add hooks for a range of events within Python and determine how to respond. 实质上,这将允许您为Python中的一系列事件添加钩子并确定如何响应。 For example, you can listen to all import events and determine whether to allow or fail them at runtime based on exactly which module is being imported, or listen to compile events to manage all runtime compilation. 例如,您可以监听所有import事件,并根据要导入的模块确定是在运行时允许还是失败,或者监听compile事件以管理所有运行时编译。 You can do this from Python code (with sys.addaudithook ) or C code (with PySys_AddAuditHook ). 您可以使用Python代码(使用sys.addaudithook )或C代码(使用PySys_AddAuditHook )执行此操作。

The Programs/spython.c file in the repo is a fairly thorough example of auditing from C, while doing it from Python looks more like this (taken from my talk about this PEP): repo中的Programs / spython.c文件是一个相当彻底的C审计示例,而从Python执行它看起来更像是这样(取自对此PEP的讨论):

import sys

def prevent_bitly(event, args):
    if event == 'urllib.Request' and '://bit.ly/' in args[0]:
        print(f'WARNING: urlopen({args[0]}) blocked')
        raise RuntimeError('access to bit.ly is not allowed')

sys.addaudithook(prevent_bitly)

The downside of this approach is you need to build and distribute your own version of Python, rather than relying on a system install. 这种方法的缺点是您需要构建和分发自己的Python版本,而不是依赖于系统安装。 However, in general this is a good idea if your application is dependent on embedding as it means you won't have to force users into a specific system configuration. 但是,一般来说,如果您的应用程序依赖于嵌入,这是一个好主意,因为这意味着您不必强制用户进入特定的系统配置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM