因此,我有一些未经验证的脚本,这些脚本是动态生成的并且需要运行。所以我不得不限制访问模块,它在我的情况是io
,os
,shutil
,等...
现在这是我尝试过的
from types import ModuleType
def generate_empty_globals():
return ModuleType("__main__").__dict__
module_locker = """
import os, sys, io
def empty_module(module):
for x in dir(module):
setattr(module, x, None)
empty_module(os)
empty_module(sys)
empty_module(io)
"""
my_module = generate_empty_globals()
code = """ ... """
exec(module_locker, my_module)
exec(code, my_module)
现在,在上述方法中,我已经导入了模块,并将其中的每个函数变量设置为None,因此,如果运行未知代码并导入该库,则不会重新导入该库,因为该库已被导入,这提供了一个很好的层次安全性,但与此同时您拥有这样的代码
import os
import importlib
importlib.reload(os)
因此,他们可以再次访问模块。因此,我认为我可以通过阻止importlib本身的reload方法来阻止它们,但是不幸的是,给出的某些代码依赖于该reload功能。现在,我有了一个新主意,该主意基本上是ast
用来修改代码结构并删除那些导入语句的,但是我不知道该怎么做,因此有什么方法可以不依赖平台特定的方法来做到这一点。
编辑
限制模块访问的简单方法(仅)。为了允许使用模块,我将使用特殊的模块或说api。
首先,我认为您应该真正考虑一种替代方法,例如使用子进程作为受更严格限制的用户运行。如果双手被绑住了,由于某种原因而被迫以这种方式实现它,则您可能需要研究importlib钩子(在进行记录后说,使用导入钩子解决问题不是一个好主意)。
导入挂钩有两种类型:元挂钩和路径挂钩。在导入处理开始之前,在进行任何其他导入处理之前,将调用元挂钩(以便元挂钩可以覆盖sys.path处理,冻结模块甚至内置模块)。要注册一个meta挂钩,只需将finder对象添加到sys.meta_path(已注册的meta挂钩的列表)。
importlib.abc。MetaPathFinder
表示元路径查找器的抽象基类。为了兼容性,这是Finder的子类。
版本3.3中的新功能。
find_spec(全名,路径,目标=无)
查找指定模块规格的抽象方法。如果这是顶级导入,则路径将为“无”。否则,这是在搜索子包或模块,并且path将是来自父包的path的值。如果找不到规范,则返回None。传入时,目标是发现者可以用来对返回的规格进行更有根据的猜测的模块对象。importlib.util.spec_from_loader()对于实现具体的MetaPathFinders可能有用。
3.4版的新功能。
find_module(全名,路径)
查找指定模块的加载程序的旧方法。如果这是顶级导入,则路径将为“无”。否则,这是在搜索子包或模块,并且path将是来自父包的path的值。如果找不到加载程序,则返回None。
如果定义了find_spec(),则提供向后兼容的功能。
在版本3.4中进行了更改:调用时返回None而不是引发NotImplementedError。可以使用find_spec()提供功能。
从3.4版开始不推荐使用:改为使用find_spec()。
invalidate_caches()
可选方法,该方法在调用时应使查找程序使用的任何内部缓存无效。当使sys.meta_path上所有查找程序的缓存无效时,由importlib.invalidate_caches()使用。
在版本3.4中进行了更改:调用而不是NotImplemented时返回None。
稍微玩一下,我就能制作一个导入钩子,该钩子将检查请求的模块是否在已批准的模块列表中。如果是,它将使用默认导入器导入模块。如果不是,则会引发错误。
我可以通过这样的解决方案想到两个主要问题(肯定还有更多)。首先,顶级模块可以导入许多其他模块。其次,如果您需要允许脚本导入sys或importlib,则它们可以轻松地找到解决导入限制的方法。
import sys
import importlib
class MyImporter():
original_importers = sys.meta_path
approved = ['os']
@classmethod
def find_spec(cls, fullname, path, target=None):
if fullname not in cls.approved:
raise RuntimeError('Permission for module {} not approved'.format(fullname))
for importer in cls.original_importers:
spec = importer.find_spec(fullname, path, target)
if spec is not None:
return spec
return None
if __name__ == '__main__':
importlib.abc.MetaPathFinder.register(MyImporter)
sys.meta_path = [MyImporter]
import os
import argparse # fails because argparse is not in approved modules
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句