Register global import hooks in python

Question:

I want to add libraries access control to my installation of python and I wanted to know if there is some way to hook into the import system, so that I can run a script to check if a python program is allowed to import libraries, to block untrusted modules from importing dangerous native modules that could leak information on my system, like os.

While researching by myself, I found out about PEP 302, which sounds like what I am looking for, but I couldn’t find how to register those hooks installation-wide.

Would someone be able to tell me if there is a way in python to add such an import hook to all imports on the system rather than only on the currently executing program?

Asked By: arthuro555

||

Answers:

You can change the import of modules by implementing you own custom import loader object. A starting point in the documentation can be found here: https://docs.python.org/3/library/importlib.html

What you need to do is to create a loader that will act on the packages you want to check on, and then either load them, or raise a desired exception. In the case of modules what are not in your access control list, you should return None, this makes the import machinery load them normally. I have create a minimal example of this type of functionality that you can start from and extend to build your desired functionality.

import sys
import importlib

class ImportInterceptor(importlib.abc.Loader):
    def __init__(self, package_permissions):
        self.package_permissions = package_permissions

    def find_module(self, fullname, path=None):
        if fullname in self.package_permissions:
            if self.package_permissions[fullname]:
                return self
            else:
                raise ImportError("Package import was not allowed")

    def load_module(self, fullname):
        sys.meta_path = [x for x in sys.meta_path[1:] if x is not self]
        module = importlib.import_module(fullname)
        sys.meta_path = [self] + sys.meta_path
        return module


if not hasattr(sys,'frozen'):
    sys.meta_path = [ImportInterceptor({'textwrap': True, 'Pathlib': False})] + sys.meta_path


import textwrap

print(textwrap.dedent('    test'))
# Works fine

from pathlib import Path
# Raises exception

Note that the loader removes itself from sys.meta_path when loading the package. This is to avoid an infinite loop where it keeps calling itself every time it tries to load the module “for real”.

Answered By: Vincent
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.