10

Here is the scenario, my website has some unsafe code, which is generated by website users, to run on my server.

I want to disable some reserved words for python to protect my running environment, such as eval, exec, print and so on.

Is there a simple way (without changing the python interpreter, my python version is 2.7.10) to implement the feature I described before?

9
  • 1
    Is your website designed to be a sandbox in the first place, or is this something that's happening because people are trying to attack your site? Commented Oct 21, 2015 at 6:19
  • you can validate user input before processing anything Commented Oct 21, 2015 at 6:20
  • It is designed to be a sandbox which allow users execute python codes to access user-defined data which is located on my server. Commented Oct 21, 2015 at 6:21
  • eval is not a keyword, but a function. eval = 8; print eval; Best bet for validating code is to parse it into AST, then scan the tree for unsafe things. However... see this. Commented Oct 21, 2015 at 6:23
  • Thanks for reminding eval and the suggestion. Commented Oct 21, 2015 at 6:31

2 Answers 2

7

Disabling names on python level won't help as there are numerous ways around it. See this and this post for more info. This is what you need to do:

For CPython, use RestrictedPython to define a restricted subset of Python.

For PyPy, use sandboxing. It allows you to run arbitrary python code in a special environment that serializes all input/output so you can check it and decide which commands are allowed before actually running them.

Since version 3.8 Python supports audit hooks so you can completely prevent certain actions:

import sys

def audit(event, args):
    if event == 'compile':
        sys.exit('nice try!')

sys.addaudithook(audit)

eval('5')

Additionally, to protect your host OS, use

  • either virtualization (safer) such as KVM or VirtualBox

  • or containerization (much lighter) such as lxd or docker

In the case of containerization with docker you may need to add AppArmor or SELinux policies for extra safety. lxd already comes with AppArmor policies by default.

Make sure you run the code as a user with as little privileges as possible.

Rebuild the virtual machine/container for each user.

Whichever solution you use, don't forget to limit resource usage (RAM, CPU, storage, network). Use cgroups if your chosen virtualization/containerization solution does not support these kinds of limits.

Last but not least, use timeouts to prevent your users' code from running forever.

Sign up to request clarification or add additional context in comments.

1 Comment

while technically you can sandbox python in the interpreter I strongly recommend against relying on it. Historically weather it's python, Java or other languages having "languages with a full system interface/feature set where you can also sandbox them" is plagued with security vulnerabilities. And even linux containers should not run fully untrusted groups (at worst semi-trusted code). Technically micro-vms (e.g. firecracker) or cross compiling to a system designed to run untrusted code (wasm) would be preferable. Through that isn't always practical. And a lot of untrusted is semi-trusted.
0

One way is to shadow the methods:

def not_available(*args, **kwargs):
    return 'Not allowed'

eval = not_available
exec = not_available
print = not_available

However, someone smart can always do this:

import builtins
builtins.print('this works!')

So the real solution is to parse the code and not allow the input if it has such statements (rather than trying to disable them).

5 Comments

Good for you! I also try to disable some specific modules such as os, threading and builtins...
Unfortunately, this won't work for exec in Python 2.7 since exec is a statement, not a function, so any attempt to assign to exec raises SyntaxError: invalid syntax. And to make it work for print you need from __future__ import print_function to disable the print statement.
@diaosihuai: You can do a simple string or regex test to see if the user code contains an exec statement. OTOH, it's probably better to use ast to process the user code.
@PM 2Ring use ast to check whether user code contains these sensitive keywords and stop if the result is True. So the user code will not really run until they pass the ast test?
"So the real solution is to parse the code and not allow the input if it has such statements (rather than trying to disable them)." isn't a real solution. It's pretty easy to bypass code parsing blocking with obfuscation. That just kicks the can a bit. This answer is much better.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.