Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
86 views
in Technique[技术] by (71.8m points)

Is there a way to limit python's access to storage programmatically?

So I had a few unverified scripts which are generated dynamically and are required to run. So I had to limit the access to a module which in my case is io, os, shutil, etc...

Now this is something I have tried

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)

Now in the above approach i already import the modules and set every function variable in them to None, so that if the unknown code runs and imports the library, the library would not be re imported because the library was already imported, this provides good level of security but at the same time you have code s like this one

import os 
import importlib

importlib.reload(os)

which thus allows them the access the modules once again. So I thought i could block them by blocking the reload method of importlib itself but unfortunately some code that was given relied on that reload ability. Now I had a new idea in my mind which is basically use ast to modify the code structure and remove those import statements but I do not know how to do that, so is there any way to do this without relying on platform specific methods.

edit

Simply a way to restrict the module access (only). and for allowance of modules I will use a special module or say api.

question from:https://stackoverflow.com/questions/65847216/is-there-a-way-to-limit-pythons-access-to-storage-programmatically

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Let me start by saying that I think you should really consider an alternative such as using a subprocess run as a more restricted user. If your hands are tied and you're being forced to implement it this way for some reason, you might want to look into importlib hooks (after you go on the record stating it's a bad idea to solve the problem using import hooks).

From PEP 302 - New Import Hooks

There are two types of import hooks: Meta hooks and Path hooks. Meta hooks are called at the start of import processing, before any other import processing (so that meta hooks can override sys.path processing, frozen modules, or even built-in modules). To register a meta hook, simply add the finder object to sys.meta_path (the list of registered meta hooks.)

importlib.abc.MetaPathFinder

An abstract base class representing a meta path finder. For compatibility, this is a subclass of Finder.

New in version 3.3.

find_spec(fullname, path, target=None)

An abstract method for finding a spec for the specified module. If this is a top-level import, path will be None. Otherwise, this is a search for a subpackage or module and path will be the value of path from the parent package. If a spec cannot be found, None is returned. When passed in, target is a module object that the finder may use to make a more educated guess about what spec to return. importlib.util.spec_from_loader() may be useful for implementing concrete MetaPathFinders.

New in version 3.4.

find_module(fullname, path)

A legacy method for finding a loader for the specified module. If this is a top-level import, path will be None. Otherwise, this is a search for a subpackage or module and path will be the value of path from the parent package. If a loader cannot be found, None is returned.

If find_spec() is defined, backwards-compatible functionality is provided.

Changed in version 3.4: Returns None when called instead of raising NotImplementedError. Can use find_spec() to provide functionality.

Deprecated since version 3.4: Use find_spec() instead.

invalidate_caches()

An optional method which, when called, should invalidate any internal cache used by the finder. Used by importlib.invalidate_caches() when invalidating the caches of all finders on sys.meta_path.

Changed in version 3.4: Returns None when called instead of NotImplemented.

Just playing around with it a little bit, I was able to make an import hook that will check if the requested module is in a list of approved modules. If it is, it imports the module using the default importers. If not, it raises an error.

I can think of two major problems (and there are surely more) with a solution like this. First, a top-level module can import dozens of other modules. Second, if you ever need to allow a script to import sys or importlib, they could easily find a way around the import restrictions.

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...