実行時に入力されたコードをコンパイルして実行するって大変そうだ…

元ネタ:ASP.NET DLLの読み込みについて - .NET開発者中心(元VB研)会議室

こういうのって、個人で使う趣味レベルの物か検証やモック?の代わりとしてしか作った事ないけど、実業務で使うとなると相当大変そう。
しかもサーバーサイドでコンパイル、実行とか!変なコードが動いたら、サーバーがダウンしてしまう。


試しに掲示板の回答にも書いたコードを悪意を持って改変してみる。

using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

public partial class _Default : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    var src = @"public class Test
{
  public int Add(int a, int b)
  {
    System.AppDomain.Unload(System.AppDomain.CurrentDomain); // 悪意あり過ぎ!!
    return a + b;
  }
}";
    var provider = new CSharpCodeProvider();
    var param = new CompilerParameters();
    param.GenerateInMemory = true;

    var result = provider.CompileAssemblyFromSource(param, src);

    var asm = result.CompiledAssembly;
    var type = asm.GetType("Test");
    var method = type.GetMethod("Add");
    var instance = asm.CreateInstance(type.FullName);
    var addResult = (int)method.Invoke(instance, new object[] { 1, 2 } );

    this.txt.Text = addResult.ToString();
  }
}

これを実行すると、サーバーから結果が返って来なかった。こんなのどうするんだろうね?コンパイル後の型に、適切なセキュリティの属性が付与されていなかったら実行しないとかするのかな?
こんな感じのコードだと、セキュリティ例外が発生して悪意あるコードは実行されない。

using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;

public partial class _Default : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
    var src = @"using System.Security.Permissions;
[SecurityPermission(SecurityAction.Deny, Flags = SecurityPermissionFlag.AllFlags)] // 適切なセキュリティの属性を付与
public class Test
{
  public int Add(int a, int b)
  {
    System.AppDomain.Unload(System.AppDomain.CurrentDomain); // 悪意あり過ぎ!!
    return a + b;
  }
}";
    var provider = new CSharpCodeProvider();
    var param = new CompilerParameters();
    param.GenerateInMemory = true;

    var result = provider.CompileAssemblyFromSource(param, src);

    var asm = result.CompiledAssembly;
    var type = asm.GetType("Test");
    var method = type.GetMethod("Add");
    var instance = asm.CreateInstance(type.FullName);
    var addResult = (int)method.Invoke(instance, new object[] { 1, 2 } ); // ここでセキュリティ例外が発生するので、悪意あるコードは実行されない。

    this.txt.Text = addResult.ToString();
  }
}

ここらへんってちゃんと勉強してないんだよな〜、少し調べる機会をくれた質問者に感謝。


あと無限ループ対策はどうするんだろ?タイムアウト時間を決めて、別スレッドで動かしてタイムアウト時間を経過しても結果が返ってこない場合は強制終了するとか。
この間にクライアントにはレスポンスは返せないので、ユーザーはえらく待たされるんだろうな〜。てか、クライアントが非同期通信でリクエストを投げたら良いのかな?
試してないので分かりませんが、こんな方法でうまくいくのかな〜?