Embedded IronPython Security
Asked Answered
S

2

6

I am embedding IronPython into my game engine, where you can attach scripts to objects. I don't want scripts to be able to just access the CLR whenever they want, because then they could pretty much do anything.

Having random scripts, especially if downloaded from the internet, being able to open internet connections, access the users HDD, or modify the internal game state is a very bad thing.

Normally people would just suggest, "Use a seperate AppDomain". However, unless I am severely mistaken, cross-AppDomains are slow. Very slow. Too slow for a game engine. So I am looking at alternatives.

I thought about compiling a custom version of IronPython that stops you from being able import clr or any namespace, thus limiting it to the standard library.

The option I would rather go with goes along the following lines:

__builtins__.__import__ = None #Stops imports working
reload = None #Stops reloading working (specifically stops them reloading builtins
          #giving back an unbroken __import___!

I read this in another stack overflow post. Assume that instead of setting __ builtins_._ import__ to none, I instead set it to a custom function that lets you load the standard API.

The question is, using the method outlined above, would there be any way for a script to be able to be able to get access to the clr module, the .net BCL, or anything else that could potentially do bad things? Or should I go with modifying the source? A third option?

Shantay answered 27/5, 2012 at 17:4 Comment(0)
T
3

The only way to guarantee it is to use an AppDomain. I don't know what the performance hit is; it depends on your use case, so you should measure it first to make sure that it actually is too slow.

If you only need a best-effort system, and if the scripts don't need to import anything, ever, and you supply all of the objects they need from the host, then your scheme should be acceptable. You can also avoid shipping the Python standard library, which will save some space.

You'll want to check the rest of the builtins for anything that might talk to the outside world; open, file, input, raw_input, and execfile come to mind, but there may be others. exec might be an issue as well, and as it's a keyword it might be trickier to turn off if there are openings there. Never underestimate the ability of a determined attacker!

Tutty answered 29/5, 2012 at 16:10 Comment(2)
Normally I wouldn't bother to go to much effort, because if they have the .exe/.dll on their local computer, they are able to modify it regardless. But it would be nice to have scripting for game maps, which would be able to be downloaded.Shantay
@Shantay what approach in this answer did you do? The AppDomain or having your own custom builtins import? If it is the builtints import how did you populate it? I want to try a similar approach by trying to remove the __import__ variable. var scope = _engine.GetBuiltinModule(); scope.RemoveVariable("__import__")Elam
Z
3

I have embedded Iron Python in apps before and shared similar security concerns. What I did to help mitigate the risk was to create special objects just for the scripting run-time that were essentially wrappers around my core objects that only exposed "safe" functionality.

Another benefit from creating objects just for scripting is that you can optimize them for scripting with helper functions that make your scripts more terse and tidy.

Appdomain or not, there is nothing stopping somebody from loading an external .py module in their script.... Its a price you pay for the flexibility.

Zeitler answered 6/11, 2012 at 14:31 Comment(2)
Its not so much the loading of external .py modules, its more loading the inbuilt clr module and using reflection to access stuff that they aren't supposed to. Using reflection they would theoretically be able to import access to the file system and network, so they could easily be able to download viruses or trojans. All through a script designed to extend a game or app in an easy to use way.Shantay
Just shooting from the hip here: What if you add a 'vetting' module to your script import function that loads the script in a sandbox of some sort, and then checks which assemblies have been loaded. This way you could reference the assemblies against or to a blacklist/whitelist and only allow 'safe' scripts to be importedZeitler

© 2022 - 2024 — McMap. All rights reserved.