Sign in to follow this  

[.net] Security with Scripting

This topic is 4656 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm taking advantage of C# to have some pretty cool "scripting" ability in my game. Essentially, the user can write a DLL for the map that contains some custom data. There are interfaces they can inherit, and then the game sends messages to the DLL allowing the user to do whatever they want with them. It should go without saying that this is a scary thought, especially considering users will be able to share these DLLs over a lobby type chat system. However, by setting the security permissions right, there isn't much permanent harm they can do. While not permanent, I still find it incredibly easy to go ahead and crash the host program. All it would take is an infinite loop. A more subtle way would be through System.Windows.Forms...or any of hundreds of possibilities. Granted, a user doing writing those kind of nonsense "scripts" would quickly be ignored, but I would rather prevent it in the first place. The infinite loop can be solved with some simple threading. The rest is a little more complicated, and I can't think of any way to stop it. It would be amazingly easy if I could just set it up so they can only use certain namespaces (System and the game namespace exposing allowable functions)...but it doesn't seem like I can do that. If anyone can give some insight into security issues like these I would love to hear it. Otherwise I'm going to have to scrap the idea or just trust the users to play nice (haha).

Share this post


Link to post
Share on other sites
I've been meaning to get myself up to speed in this area, so I don't know much at the moment, but this seems like a good article on what you want to do. The .NET Configuration Tool is interesting to play with if you want to quickly see what's possible (try creating your own permission set).

Oh and to actually tie this in with what you want to do, this page discusses how to create an AppDomain with restricted permissions. You can execute user assemblies in that AppDomain for security.

Share this post


Link to post
Share on other sites
Thanks for the links mutex, they will help.

...but...

Common sense tells me that the app domain switching would be slow to say the least. Some comments on other message boards verify this. My system was going to be set up so that the entire game itself would be run via the scripting method. The number of app domain switches could very well make that the bottleneck, which is completely unacceptable.

I'd like to hear from someone else who has tried this.

My other option would be writing a Managed C++ wrapper around Lua. It would take more work initially but could solve the problems I'm worrying about now, and security would be much less of an issue.

Share this post


Link to post
Share on other sites
Well, then, if you don't want to use AppDomains, then what you can do is when you decide to load the assembly containing the script, check it's referenced assemblies, to make sure that it only references allowed assemblies (you can require that they not reference mscorlib as well.) In this way you could provide the assemblies with a set of allowed assemblies they can reference containing all of the utility methods (like math functions) that they require.

Share this post


Link to post
Share on other sites
But wouldn't you still be able to use reflection to get at any assembly that happened to be loaded? I think you'd have to disallow access to Type.GetType(string) somehow. And yeah, cross-AppDomain access appears to be quite slow. Maybe there's a way to temporarily reduce the security of the current thread or AppDomain.

Share this post


Link to post
Share on other sites
Quote:
Original post by Washu
Well, then, if you don't want to use AppDomains, then what you can do is when you decide to load the assembly containing the script, check it's referenced assemblies, to make sure that it only references allowed assemblies (you can require that they not reference mscorlib as well.) In this way you could provide the assemblies with a set of allowed assemblies they can reference containing all of the utility methods (like math functions) that they require.

That would work great

...except... (there's always an exception [headshake])

I had planned on precompiling the script file for faster load times in the actual game. Sounds good, except that it could leave the possibility open to someone writing a Managed C++ dll and manually replacing the other one. This Managed C++ could then call whatever unmanaged code it wants and I'm S.O.L. I would have to set the permissions of the entire application to disallow unmanaged code, something I can't do since there are a few unmanaged things I call myself. I would also have to disallow reading/writing files, etc.

Even if I compiled the C# code at game load time there is still no way to be sure they don't call unmanaged code. It appears that I'm right back to the AppDomain issue.

Share this post


Link to post
Share on other sites
Quote:
Original post by Raloth
Quote:
Original post by Washu
Well, then, if you don't want to use AppDomains, then what you can do is when you decide to load the assembly containing the script, check it's referenced assemblies, to make sure that it only references allowed assemblies (you can require that they not reference mscorlib as well.) In this way you could provide the assemblies with a set of allowed assemblies they can reference containing all of the utility methods (like math functions) that they require.

That would work great

...except... (there's always an exception [headshake])

I had planned on precompiling the script file for faster load times in the actual game. Sounds good, except that it could leave the possibility open to someone writing a Managed C++ dll and manually replacing the other one. This Managed C++ could then call whatever unmanaged code it wants and I'm S.O.L. I would have to set the permissions of the entire application to disallow unmanaged code, something I can't do since there are a few unmanaged things I call myself. I would also have to disallow reading/writing files, etc.

Even if I compiled the C# code at game load time there is still no way to be sure they don't call unmanaged code. It appears that I'm right back to the AppDomain issue.


Strongly sign your assembly then. This will prevent it from being replaced by a malicious assembly.

Share this post


Link to post
Share on other sites
I'm assuming you are talking about the DirectX SDK, in which case I've already looked at that sample. It doesn't do quite what I want to.

[edit] The Evidence parameter of the compiler when I make the code looks like it does what I want to do. However, I can't figure out at all how to use it.

[Edited by - Raloth on March 10, 2005 8:28:08 PM]

Share this post


Link to post
Share on other sites
Raloth, have you actually tried and profiled the multi-AppDomain solution? I would always give it a try because AppDomains are *the* solution to have parts of an app run under more restrictive security settings. Furthermore you will be able to unload the script dll by unloading the AppDomain. Always keep in mind that most games are not CPU limited.

There are several things you can do to minimize boundary crossing. Most of the time the client-code is called at only one place of the gameloop. Load some kind of proxy dll into the second AppDomain which will provide an interface to most of the datamanipulation necessary for the game. Then, when the script requires some data, let the proxy pull it over the boundary and cache it. The next time it is accessed get it from the cache. When the script is done flush all data changes back to the main AppDomain. This can minimize the number of cross-AppDomain calls.


Regards,
Andre

Share this post


Link to post
Share on other sites
I have found a solution more elegant than I could have hoped for:

[SecurityPermissionAttribute(SecurityAction.PermitOnly, Flags = SecurityPermissionFlag.Execution)]
By putting this in front of any method calls (or objects) involved with the actual scripting, I can change the security for just that call (or object).

[smile]

I may still have to look into AppDomains in order to unload the custom scripts, but there is no reason I can't simply shove all of the game data in the same AppDomain so there is no overhead. It's not needed while the user is in the lobby anyway, so it has the added benefit of saving (a minute amount of) memory.

Share this post


Link to post
Share on other sites
I have a feeling that if the called code creates a new thread, that thread will not have the restritced permissions. You might want to check it out.

Share this post


Link to post
Share on other sites
Quote:
Original post by SOS
I have a feeling that if the called code creates a new thread, that thread will not have the restritced permissions. You might want to check it out.

Ah...but the called code does not have the permission to create the thread in the first place. =)

Share this post


Link to post
Share on other sites

This topic is 4656 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this