
Hi, I’ve been lurking for a while. This is my first real post in a long time. This is a proposal for a system-less python; that is, a version of python that does not have file or other inappropriate access to the os. The idea is to provide a python environment capable of safely running insecure scripts. The inspiration and obvious use case for this is an addition to or replacement for Javascript scripting in a web browser. Another use might be for scripting a spreadsheet, such as Excel. I do not think this needs to be a separate version of Python. The disable feature could be controlled by a command line flag, which would also have other uses described below. For an embedded system, this could be compiled in somehow. I don’t think the changes to the language would be all that great. The only built in change would be disabling the open function call, so there could be no local file access. The next issue is the standard library, a lot of which would have to be disabled. Certainly the os and subprocess modules would not be allowed. On the other side, there should be no restrictions on, for example, collections or strings. The biggest problem is third party imports. We can’t just disallow them. The whole point of a browser plug in would be to allow gui. What I have in mind is a means whereby imports could be white-listed (apologies for my un-pc phrasing.) That same command line switch (maybe -r for restricted) could take an argument for a special python syntax configuration file which would be loaded before other processing is done, and would be unalterable, and perhaps invisible, to the program scripts. from restrict import allow_imports, import_config, python_config allow_imports (( ‘collections’, ‘wx’, ‘pandas’, )) etc. Imports not specified in the list would be disallowed by the import mechanism. White-listing imports would also have uses for a safe pickle system. Note that this doesn’t break any existing code. No command line switch, business as usual, everything; command line switch, import restrictions and configurations apply. I think once we add such a configuration file, we’ll find all sorts of other uses for it. One thought is a generalized, and again read-only, means of configuring all imports: import_config (‘pandas’ : {‘allow_disk’ : False,}) import_config (‘wx’ : {‘allow_file_dialogs’ : False,}) import_config (‘subprocess’ : {‘allow_only’ : ‘/safe_directory’,}) If an import module had no configuration in the config file, nothing would would change. If it does, the import mechanism would somehow pass the config dictionary to the import start up. I’m not jived well enough on the mechanics of import to know how this would work, but again, it wouldn’t break existing code, as if there’s no config, nothing changes. The python system configuration could go in the same file: python_config ({‘allow_open’ : False}) The generalized case of restricting various systems has a whole lot of cases. For a web browser, you might want to restrict disk access. For a different application, you might want no gui or network access. Much of this could be flushed out later. We’d probably want to add two new exceptions: IllegalOpen, for an open call when restricted, and UnsupportedImport for an unauthorized import. I’m thinking for an interpreter embedded in a web browser, there would a special import like in embedded systems now: import firefox as ff ff.web_import (‘url’, ‘module’) ff.gdi.drawtext (‘mystring’) Input = ff.input.input_string () A standard import would import the package from a local system, including binary modules. A special web_import might import a python-only module from a web server. For the first step, and following KISS, I see the following changes. 1)Allow the open built in function to be conditionally disabled. 2)Add the command line switch and read only configuration for restricting allowed imports. 3)Sort through the standard library to figure out what should be allowed in a system-less configuration and what should not. 4)Add appropriate exceptions This concept would require a whole lot of changes down the road, particularly to binary imports; that would have to be flushed out after the initial changes, and by third party module developers. That’s it; thank you for your consideration. Robert Kaplan

On Mon, Jul 20, 2020 at 2:14 AM Robert <rk546394@gmail.com> wrote:
This has been proposed many MANY times. It never really works well, because Python is incredibly introspectable. Consider this:
1.0.__class__.__bases__[0].__subclasses__()
Behold, a probably-complete list of every class currently loaded. Do you want to try to guarantee that not one of them will let the user escape the jail? Or this: try: 1/0 except ZeroDivisionError as e: e.__traceback__.tb_frame.f_globals["__builtins__"].__import__("importlib") That'll import a module. To create a restricted Python, you either have to restrict it so much that it doesn't feel like a full language any more, or you constantly have to be on the lookout for leaks. Alternatively, do it all at an external level: for instance, a chroot jail, or process-based permissions. That's a lot more reliable, but it's much harder to sandbox just part of your app (eg the user-provided code). ChrisA

Hi, Robert, I learned about an existing RestrictedPython implementation through Zope/Plone. I can see that it differs from your ideas in some ways, but I think at heart it gets to what you're trying to solve for. Have you read about it? https://restrictedpython.readthedocs.io/en/latest/idea.html Since your post doesn't seem to mention it I thought I'd bring it to your attention. – Michael On Sun, Jul 19, 2020 at 12:18 Robert <rk546394@gmail.com> wrote:

I'm making [a platform for learning Python]( https://github.com/alexmojaki/futurecoder) which needs to allow users to run arbitrary Python code on the server. Each user gets their own process and I use `import resource; resource.setrlimit(resource.RLIMIT_NOFILE, (0, 0))` to prevent opening any files. This also prevents starting any processes. If there's a way to work around this, someone please tell me. Once the limit is set, you can't import any new modules. How well does this solve your use case? On Sun, Jul 19, 2020 at 6:16 PM Robert <rk546394@gmail.com> wrote:

On Mon, Jul 20, 2020 at 2:14 AM Robert <rk546394@gmail.com> wrote:
This has been proposed many MANY times. It never really works well, because Python is incredibly introspectable. Consider this:
1.0.__class__.__bases__[0].__subclasses__()
Behold, a probably-complete list of every class currently loaded. Do you want to try to guarantee that not one of them will let the user escape the jail? Or this: try: 1/0 except ZeroDivisionError as e: e.__traceback__.tb_frame.f_globals["__builtins__"].__import__("importlib") That'll import a module. To create a restricted Python, you either have to restrict it so much that it doesn't feel like a full language any more, or you constantly have to be on the lookout for leaks. Alternatively, do it all at an external level: for instance, a chroot jail, or process-based permissions. That's a lot more reliable, but it's much harder to sandbox just part of your app (eg the user-provided code). ChrisA

Hi, Robert, I learned about an existing RestrictedPython implementation through Zope/Plone. I can see that it differs from your ideas in some ways, but I think at heart it gets to what you're trying to solve for. Have you read about it? https://restrictedpython.readthedocs.io/en/latest/idea.html Since your post doesn't seem to mention it I thought I'd bring it to your attention. – Michael On Sun, Jul 19, 2020 at 12:18 Robert <rk546394@gmail.com> wrote:

I'm making [a platform for learning Python]( https://github.com/alexmojaki/futurecoder) which needs to allow users to run arbitrary Python code on the server. Each user gets their own process and I use `import resource; resource.setrlimit(resource.RLIMIT_NOFILE, (0, 0))` to prevent opening any files. This also prevents starting any processes. If there's a way to work around this, someone please tell me. Once the limit is set, you can't import any new modules. How well does this solve your use case? On Sun, Jul 19, 2020 at 6:16 PM Robert <rk546394@gmail.com> wrote:
participants (4)
-
Alex Hall
-
Chris Angelico
-
Michael Smith
-
Robert