1

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?

arthuro555
  • 134
  • 2
  • 10
  • Welcome to Stackoverflow. StackOverflow is **not** a code-writing service. Please post what you have tried, along with your inputs and expected outputs. – Chris Jan 31 '19 at 08:41
  • Well, where should I Ask then? – arthuro555 Jan 31 '19 at 08:45
  • 4
    Hi, welcome to stackoverflow. I'm so sorry for the rude welcome you received from Chris and Jaba. This is sadly not an uncommon a part of the community culture but something that stackexchange is trying hard to change. Your question is perfectly reasonable, and every question that can be answered by rigorously studying documentation should not be deferred to google. That defies the entire point of this site. I have submitted an answer that I hope will help you along your way. – Vincent Jan 31 '19 at 09:09
  • 2
    Signed in to upvote. This question is useful, and has some original research. It's perfectly valid to read a specification of an esoteric and internal part of Python, and feel like you need a practical example (of something that the OP defined pretty well). – Rol Mar 26 '21 at 15:15

1 Answers1

6

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".

Vincent
  • 536
  • 4
  • 8
  • Should I write that in every python file I were I want to have this system or does it somehow registers for the entier system? – arthuro555 Jan 31 '19 at 11:21
  • Thanks by the way! – arthuro555 Jan 31 '19 at 11:35
  • It doesn't register for the entire system, so I would advice creating a module yourself if you need to use it widely. – Vincent Jan 31 '19 at 12:53
  • What do you mean? – arthuro555 Jan 31 '19 at 17:26
  • 1
    So for instance you could put all the code (except the tests at the bottom) into a file called `ImportInterceptor.py` and then at the top of each file where you want it to work you start out with Import `ImportInterceptor` if you want it to always run automatically before any file is run you could look at this answer for guidence: https://stackoverflow.com/questions/32184440/making-python-run-a-few-lines-before-my-script – Vincent Feb 04 '19 at 12:34