如何解决有没有办法以编程方式限制python对存储的访问?
所以我有一些未经验证的脚本,它们是动态生成的,需要运行。所以我不得不限制对模块的访问,在我的例子中是 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 本身的重新加载方法来阻止它们,但不幸的是,一些代码依赖于这种重新加载能力。现在我脑子里有了一个新想法,基本上就是用ast
来修改代码结构,去掉那些import语句,但是我不知道怎么做,那么有没有不依赖平台的方法呢?具体方法。
编辑
只是一种限制模块访问的方法(仅限)。对于模块的允许,我将使用一个特殊的模块或说 api。
解决方法
首先让我说我认为您应该真正考虑替代方案,例如使用子进程作为更受限制的用户运行。如果您的双手被束缚并且由于某种原因被迫以这种方式实现它,您可能需要查看 importlib 钩子(在您记录声明使用导入钩子解决问题是一个坏主意之后)。
导入钩子有两种类型:元钩子和路径钩子。在导入处理开始时调用元钩子,在任何其他导入处理之前(这样元钩子可以覆盖 sys.path 处理、冻结模块,甚至内置模块)。要注册元钩子,只需将 finder 对象添加到 sys.meta_path(已注册元钩子列表)。
importlib.abc.MetaPathFinder
代表元路径查找器的抽象基类。为了 兼容性,这是 Finder 的子类。
3.3 版中的新功能。
find_spec(fullname,path,target=None)
用于查找指定模块规范的抽象方法。如果 这是顶级导入,路径将为无。否则,这是一个 搜索子包或模块,路径将是 路径 来自父包。如果找不到规范,则返回 None 。传入时,target 是一个模块对象,finder 可能用于对返回的规范进行更有根据的猜测。 importlib.util.spec_from_loader() 可能有助于实现 具体的 MetaPathFinders。
3.4 版中的新功能。
find_module(fullname,path)
为指定模块查找加载器的旧方法。如果这是顶级导入,路径将为无。否则,这是对子包或模块的搜索,路径将是父包中 path 的值。如果找不到加载器,则返回 None。
如果定义了 find_spec(),则提供向后兼容的功能。
在 3.4 版更改:调用时返回 None 而不是引发 未实现错误。可以使用 find_spec() 来提供功能。
自 3.4 版起已弃用:改用 find_spec()。
invalidate_caches()
一个可选的方法,当被调用时,应该 使查找器使用的任何内部缓存无效。使用人 importlib.invalidate_caches() 当所有缓存失效时 sys.meta_path 上的发现者。
在 3.4 版更改:调用时返回 None 而不是 未实施。
只是稍微玩了一下,我就能够制作一个导入钩子来检查请求的模块是否在批准的模块列表中。如果是,则使用默认导入器导入模块。如果不是,则会引发错误。
通过这样的解决方案,我可以想到两个主要问题(肯定还有更多)。首先,一个顶级模块可以导入几十个其他模块。其次,如果您需要允许脚本导入 sys 或 importlib,他们可以轻松找到绕过导入限制的方法。
import sys
import importlib
class MyImporter():
original_importers = sys.meta_path
approved = ['os']
@classmethod
def find_spec(cls,fullname,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,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
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。