在嵌入式Python中禁用内置模块导入
我正在我的应用程序中嵌入Python3.6,我想在脚本中禁用import命令,以防止用户导入任何Python内置库。我只想使用语言本身和我自己的C++定义的模块。在嵌入式Python中禁用内置模块导入,python,c++,python-3.x,python-embedding,Python,C++,Python 3.x,Python Embedding,我正在我的应用程序中嵌入Python3.6,我想在脚本中禁用import命令,以防止用户导入任何Python内置库。我只想使用语言本身和我自己的C++定义的模块。 Py_SetProgramName(L“示例”); Py_初始化(); PyObject*mainModule=PyImport\u AddModule(“\uuuu main\uuuu”); PyObject*globals=PyModule_GetDict(主模块); //这应该行得通 std::string script1=“打
Py_SetProgramName(L“示例”);
Py_初始化();
PyObject*mainModule=PyImport\u AddModule(“\uuuu main\uuuu”);
PyObject*globals=PyModule_GetDict(主模块);
//这应该行得通
std::string script1=“打印('example')”;
PyRun_字符串(script1.c_str(),Py_file_输入,globals,nullptr);
//这不应该奏效
std::string script2=“导入随机\n”
“打印(random.randint(1,10))\n”;
PyRun_字符串(script2.c_str(),Py_file_输入,globals,nullptr);
Py_();
您知道实现这一点的方法吗?Python长期以来不可能创建一个安全的沙箱(作为起点,如果您愿意,可以跳入旧沙箱)。以下是我认为你最好的两种选择。 预先扫描代码 在执行任何操作之前,先扫描代码。您可以在Python中使用,然后遍历树,也可以使用更简单的文本搜索。这可能适用于您的场景,因为您有限制的用例-它不能推广到真正的任意代码 在您的案例中,您需要的是任何
import
语句(简单),以及任何未“批准”的顶级变量(例如,在a.b.c
中,您关心a
,对于给定的a
),可能是a.b
)。这将使您能够在运行任何不干净的代码之前失败
这里的挑战是,即使是经过三层模糊处理的代码也会绕过您的检查。例如,这里有一些方法可以导入给定的其他模块或全局模块,而import
的基本扫描无法找到这些模块或全局模块。您可能希望限制直接访问\uuuuuuuuuuuuuuuuuuuuuuu
,全局
,\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。在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()
(我希望不用说,这是一个不可能的挑战,以及为什么这种沙箱方法从未完全成功。但它可能足够好,取决于您的特定威胁模型。)
运行时审计
如果您有能力编译自己的Python运行时,您可以考虑使用(当前草案)挂钩。(免责声明:我是本PEP的作者。)有针对最新和最新版本的实现草案
本质上,这将允许您为Python中的一系列事件添加挂钩,并确定如何响应。例如,您可以侦听所有import
事件,并根据要导入的模块确定在运行时是否允许这些事件,或者侦听compile
事件以管理所有运行时编译。可以从Python代码(使用sys.addaudithook
)或C代码(使用PySys\u addaudithook
)执行此操作
repo中的文件是从C进行审计的一个相当彻底的例子,而从Python进行审计看起来更像这样(摘自关于这个PEP):
这种方法的缺点是您需要构建和分发自己的Python版本,而不是依赖于系统安装。但是,一般来说,如果应用程序依赖于嵌入,这是一个好主意,因为这意味着您不必强迫用户进入特定的系统配置。一瞥:删除eval
,exec
,sys
和os
也一样。当然,我想禁用除我自己的模块之外的所有功能。请注意,您可以通过覆盖内置项来控制所有import
语句。\uuuuu导入\uuuuu
属性和自定义函数。(这并不能使Python对恶意用户具有健壮性,但可以在您的简单示例中使用。)非常详细的回答,谢谢,我认为这是一个非常好的起点。一个问题:为什么我必须检查顶级变量?在这种情况下,什么样的变量会导致麻烦?@kovacsv我的评论开始变长,因此我在答案中添加了内容。非常感谢,现在我明白了问题的复杂性。
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)