17

I'd like to make a website where people could upload their Python scripts. Of course I'd like to execute those scripts. Those scripts should do some interesting work. The problem is that people could upload scripts that could harm my server and I'd like to prevent that. What is the option to run arbitrary scripts without harming my system - actually without seeing my system at all? Thank you

maliperica
  • 171
  • 1
  • 1
  • 3
  • There is a way to configure Python to disable unsafe functions - it was used successfully in Paint Shop Pro. Unfortunately I don't have the technical details. Plus there's the possibility of bug exploits and plain old denial-of-service by uploading an infinite loop. – Mark Ransom Sep 10 '10 at 22:14
  • That would probably be great for standalone applications run on own computer, not on a public server... – maliperica Sep 10 '10 at 22:16
  • http://codepad.org/ Will allow you to paste a script and run it in many languages including Python. – Shane Reustle Sep 11 '10 at 01:48

9 Answers9

6

"Can't be done."

Running arbitrary (untrusted) scripts and staying safe is a contradiction. You should go as far as using custom kernels, jails, vms, the like.

You can look at how http://codepad.org/about does it, it's a lot of work.

supakeen
  • 2,876
  • 19
  • 19
  • Wow, that was helpful. After your post I'm thinking of writing my own pseudo-language similar to Python to achieve my goal... – maliperica Sep 10 '10 at 22:12
  • You could tinker with the latest PyPy additions but I was assuming you wanted to offer access to cpython. – supakeen Sep 10 '10 at 22:15
  • Not really, I'd just like people to submit their code and evaluate if afterwards.... (run it and see what it does) Anyway, I'd just like to make it possible to upload some code and test it - without doing any damage - anything that lot's of people is familiar with – maliperica Sep 10 '10 at 22:18
4

I dont know in earlier versions, in Python 3 you can create functions with access to a custom scope through types.FunctionType.

def f():
  return __builtins__

f() # this will work because it has access to __builtins__
scope = {}
sandboxed = FunctionType(f.__code__,scope)
sandboxed()  # will throw NameError, builtins is not defined

the returned function has only access to whatever you supplied in the scope dictionary. I wonder if still there are hacks around this.

andres
  • 41
  • 1
  • Tested on python 2.7.3 and works exactly the same. – Jorge Vargas May 17 '12 at 06:14
  • You can easily get out of this one. I didn't manage to get `__import__` (yet), but `file` is accessible and arbitrary read/write is considered breaking the sandbox, IMO. – Blender May 07 '13 at 02:58
  • I haven't tried it myself, but the rule of thumb is that you can break out as long as you have access to double underscore attributes. So at the very least you need to whitelist the AST. – Antimony May 25 '13 at 10:31
3

there are quite a lot of web-server running untrusted python codes nowadays:

you may want to look at how they approached their problems.

or you may want to look at a different approach:

  • http://pyjs.org/ - pyjamas - python-to-javascript compiler (running client-side, switch the security problem to their side)
Lie Ryan
  • 62,238
  • 13
  • 100
  • 144
2

"Can't be done," is too harsh. JavaScript engines live in your web browser and they accept and run untrusted scripts safely. There's always the possibility of exploits, but in correct engine operation they are innocuous. There are even "slow script" checks that prevent infinite loops from denial-of-service attacking your browser, making those little alert dialogs.

Google App Engine runs a sandboxed version of the Python VM which effectively removes all the naughty native bits that let you get at the underlying system. To do this yourself in a safe manner would take some Python VM expertise.

For sanity, you could start off by removing all builtins and whitelisting the ones you want to allow users once you certify they don't touch the underlying system.

It feels like something somebody must have already done, but I don't know of any existing project that does it. :-/

cdleary
  • 69,512
  • 53
  • 163
  • 191
  • 2
    It has been tried and you can't do it properly without walking the VM/PyPy/codepad way. You'll need to disallow silly stuff like `__builtins__.__import__('sys').exit()` and the numerous other ways to get at it (locals() and the like). Also, without crippling the interpreter itself. – supakeen Sep 10 '10 at 22:41
  • So you're saying you can't do it properly without doing it properly? That much I figured. ;-) – cdleary Sep 10 '10 at 22:43
  • 2 problems: 1) javascript engines are designed ground-up as a client-side script, python is not; 2) javascript lives in your web browser, and he is asking running untrusted python server-side. I'd agree that it's doable, though it would require quite a lot of work and limits a lot of stuffs. – Lie Ryan Sep 11 '10 at 01:53
2

I think the way to do this is to run those scripts in normal Python shell, but on a virtual machine. I might be biased, because my "job" is currently to play around with VMs (universities are great!).

A new VM instance can be created and started in seconds. If you keep a few around and replace only those that get broken, you have good service, absolute security and almost no effort.

But there is one thing: Virtually all web hosts today are virtual machines and they don't support another virtual machine inside. You need a real, physical server to do this.

Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
1

If you use Linux maybe seccomp is the solution, even the mode 2 is nicer. With those you can create a new process that will fail any syscall and can only read already existing file descriptors.

Maybe using also namespaces and cgroup would help, this can be done with ctypes.

Jorge E. Cardona
  • 92,161
  • 3
  • 37
  • 44
1

You could try Ideone API - it allows Python 2 and Python 3

kuszi
  • 2,069
  • 29
  • 36
  • Ideone API evolved into Sphere Engine (http://sphere-engine.com). Now it offers much more than old Ideone API :) – Robson May 29 '17 at 08:22
1

Brett Cannon has a tentative design for doing this, last I knew, but it has not been developed. So unless you're looking to put a LOT of effort into making this happen, there currently isn't a solution publicly available.

Brett's blog is at: http://sayspy.blogspot.com/ if you want to try to read up on it, I couldn't find a direct link to his discussions about the new security design. I can't recall if I read his blog talking about it, or if it was in person where he mentioned it, sorry.

There used to be some restricted execution abilities, but they were dropped because they just didn't work.

It's not impossible to do, but it's not something that Python is able to do right now. It's something people would like, but it's not really a high priority from what I've seen.

Sean Reifschneider
  • 1,261
  • 10
  • 16
  • AFAICR, the plan was dropped because there is no way to guarantee such safety from Python itself, and an externally-enforced sandbox should be the way to go for any real security. – Lie Ryan Sep 11 '10 at 01:56
  • Yes, that is what I meant by "they just didn't work". Sorry I wasn't more clear there. I wouldn't agree that there's no way to guarantee such safety from Python, I believe Brett has a plan that would allow it, but I'd have to defer to him for the details of it one way or another. – Sean Reifschneider Oct 09 '10 at 00:18
1

trypython.org (BSD licensed source here) does a safe browser oriented version of such a sanbox in IronPython (via Silverlight/Moonlight). You may be able to mash together a headless version of this for use on a server -- but you could definitely let users distribute scripts between each other, or you could distribute these scripts to be executed within the plugin environment.

unmounted
  • 33,530
  • 16
  • 61
  • 61