スクリプトの目的でIronPythonをC#アプリケーションに統合しようとしています。また、ファイルシステム/ネットワーク/機密システムリソースへのアクセスを制限する一連のセキュリティポリシーの下でスクリプトを実行したいと思います。
調査によると、最も一般的なアプローチはCASを使用することです。これは非常にうまく機能し、ユーザーがソケットを使用したり、ファイルシステムにアクセスしたりすることはできません。ただし、スクリプトが対話する変数を挿入しようとすると、特定のパラメーターにアクセスするたびにセキュリティ例外が発生します。これは、アセンブリで定義した変数でのみ発生します。標準の.NETタイプ(辞書など)を使用すると、問題なく動作します。
私のコード:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Security.Policy;
using System.Security.Permissions;
using System.Security;
using System.IO;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
using System.Runtime.Remoting;
using System.Net;
namespace python_in_appdomain
{
[Serializable]
public class Whatever
{
public int i;
public Whatever(int i)
{
this.i = i;
}
}
class Program
{
static void Main(string[] args)
{
Remoting();
}
public static void Remoting()
{
AppDomainSetup setup = new AppDomainSetup();
Assembly thisAssembly = Assembly.GetExecutingAssembly();
setup.ApplicationBase = Path.GetDirectoryName(thisAssembly.Location);
AssemblyName name = typeof(Program).Assembly.GetName();
StrongName sn = new StrongName(
new StrongNamePublicKeyBlob(name.GetPublicKey()),
name.Name,
name.Version
);
PermissionSet pset = new PermissionSet(PermissionState.None);
pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
pset.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));
setup.PartialTrustVisibleAssemblies = new[] { sn.Name + ", PublicKey=" + sn.PublicKey.ToString() };
AppDomain domain = AppDomain.CreateDomain("Sandbox", AppDomain.CurrentDomain.Evidence, setup, pset, sn);
String script = @"
d.Add('hello', 1)
w.i = 5
";
Whatever w = new Whatever(4);
Dictionary<string, int> d = new Dictionary<string,int>();
ScriptRuntime py = Python.CreateRuntime(domain);
ScriptEngine engine = py.GetEngine("py");
ScriptScope scope = engine.CreateScope();
scope.SetVariable("w", w);
scope.SetVariable("d", d);
int result;
Console.WriteLine(w.i);
d.TryGetValue("hello", out result);
Console.WriteLine(result);
Console.WriteLine("-----");
try
{
engine.Execute(script, scope);
}
catch (Exception exc)
{
Console.WriteLine(exc.ToString());
}
w = scope.GetVariable<Whatever>("w");
d = scope.GetVariable<Dictionary<string,int>>("d");
Console.WriteLine("-----");
Console.WriteLine(w.i);
d.TryGetValue("hello", out result);
Console.WriteLine(result);
}
}
}
55行目の「wi=5」をコメントアウトすると、制限されたセキュリティ設定でプログラムが正常に実行されます。47行目でPermissionStateをUnrestrictedに設定すると、スクリプトの両方の行が正常に実行されます。表示されるエラーメッセージは次のとおりです。
System.Security.SecurityException: Request failed.
at System.Runtime.CompilerServices.RuntimeHelpers._CompileMethod(IRuntimeMethodInfo method)
at System.Reflection.Emit.DynamicMethod.CreateDelegate(Type delegateType, Object target)
at System.Dynamic.Utils.TypeExtensions.CreateDelegate(MethodInfo methodInfo, Type delegateType, Object target)
at System.Linq.Expressions.Compiler.LambdaCompiler.CreateDelegate()
at System.Linq.Expressions.Compiler.LambdaCompiler.Compile(LambdaExpression lambda, DebugInfoGenerator debugInfoGenerator)
at System.Linq.Expressions.Expression`1.Compile()
at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1)
at Microsoft.Scripting.Interpreter.DynamicInstruction`3.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
at Microsoft.Scripting.Interpreter.LightLambda.Run2[T0,T1,TRet](T0 arg0, T1 arg1)
at IronPython.Compiler.PythonScriptCode.RunWorker(CodeContext ctx)
at IronPython.Compiler.PythonScriptCode.Run(Scope scope)
at IronPython.Compiler.RuntimeScriptCode.InvokeTarget(Scope scope)
at IronPython.Compiler.RuntimeScriptCode.Run(Scope scope)
at Microsoft.Scripting.SourceUnit.Execute(Scope scope, ErrorSink errorSink)
at Microsoft.Scripting.Hosting.ScriptSource.Execute(ScriptScope scope)
at Microsoft.Scripting.Hosting.ScriptEngine.Execute(String expression, ScriptScope scope)
at Microsoft.Scripting.Hosting.ScriptEngine.Execute(String expression, ScriptScope scope)
at python_in_appdomain.Program.Remoting() in C:\Users\dave\Documents\Visual Studio 2010\Projects\IronPythonTest\IronPythonTest\Program.cs:line 7
6
The action that failed was:
Demand
The type of the first permission that failed was:
System.Security.PermissionSet
The demand was for:
<PermissionSet class="System.Security.PermissionSet"
version="1"
Unrestricted="true"/>
The granted set of the failing assembly was:
<PermissionSet class="System.Security.PermissionSet"
version="1">
<IPermission class="System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1"
Unrestricted="true"/>
<IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
version="1"
Flags="Execution"/>
</PermissionSet>
The assembly or AppDomain that failed was:
Microsoft.Dynamic, Version=1.1.0.20, Culture=neutral, PublicKeyToken=7f709c5b713576e1
The method that caused the failure was:
Int32 Run(Microsoft.Scripting.Interpreter.InterpretedFrame)
The Zone of the assembly that failed was:
Internet
The Url of the assembly that failed was:
file:///C:/Users/dave/Documents/Visual Studio 2010/Projects/IronPythonTest/IronPythonTest/bin/Debug/Microsoft.Dynamic.DLL
Unhandled Exception: System.Security.SecurityException: Request failed.
at System.Delegate.BindToMethodInfo(Object target, IRuntimeMethodInfo method, RuntimeType methodType, DelegateBindingFlags flags)
at System.Delegate.CreateDelegate(Type type, MethodInfo method, Boolean throwOnBindFailure)
at System.Dynamic.Utils.TypeExtensions.CreateDelegate(MethodInfo methodInfo, Type delegateType)
at System.Runtime.CompilerServices.CallSite`1.MakeUpdateDelegate()
at System.Runtime.CompilerServices.CallSite`1.GetUpdateDelegate(T& addr)
at System.Runtime.CompilerServices.CallSite`1.GetUpdateDelegate()
at System.Runtime.CompilerServices.CallSite`1.Create(CallSiteBinder binder)
at System.Func`2.Invoke(T arg)
at Microsoft.Scripting.Runtime.DynamicOperations.GetOrCreateSite[T](CallSiteBinder siteBinder, Func`2 factory)
at Microsoft.Scripting.Runtime.DynamicOperations.GetOrCreateSite[T1,TResult](CallSiteBinder siteBinder)
at Microsoft.Scripting.Runtime.DynamicOperations.ConvertTo[T](Object obj)
at IronPython.Runtime.PythonContext.ScopeGetVariable[T](Scope scope, String name)
at Microsoft.Scripting.Hosting.ScriptScope.GetVariable[T](String name)
at Microsoft.Scripting.Hosting.ScriptScope.GetVariable[T](String name)
at python_in_appdomain.Program.Remoting() in C:\Users\dave\Documents\Visual Studio 2010\Projects\IronPythonTest\IronPythonTest\Program.cs:line 8
3
at python_in_appdomain.Program.Main(String[] args) in C:\Users\dave\Documents\Visual Studio 2010\Projects\IronPythonTest\IronPythonTest\Program.
cs:line 31
エラーは驚くほど簡単です。この種の行動には完全に無制限のアクセスが期待されているとのことです。これを回避する方法はありますか?辞書は機能するのに変数が機能しないのはなぜですか?IronPythonに変数を辞書のように扱わせる方法はありますか?私は非常に明白な何かを逃していますか?
よろしくお願いします。
2012年12月21日更新
私はいじり続けて、うまくいく解決策を思いついた。このように(同じ権限オブジェクトを使用して)AppDomainを作成すると、すべてが機能します。
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationBase = System.Environment.CurrentDirectory;
AppDomain domain = AppDomain.CreateDomain("IPyEngine", new Evidence(), setup, pset);
理由を完全に理解しているとは言えませんが、アセンブリの証拠を提供しておらず、アセンブリを信頼リストに追加していないこともわかります。記念碑的に愚かなことを何もしていないことが確実にわかるまで、これを答えとしてマークしたくありません。