Tim*_*uri 47 c# security appdomain .net-4.0
以下是问题的原因:www.devplusplus.com/Tests/CSharp/Hello_World.
虽然之前提出了类似的问题,但网上的许多答案都有几个问题:
像这样的东西:
var evidence = new Evidence();
evidence.AddHostEvidence(new Zone(SecurityZone.Internet));
var permissionSet = SecurityManager.GetStandardSandbox(evidence);
Run Code Online (Sandbox Code Playgroud)
到目前为止,我找不到创建AppDomain并加载程序集的方法,该程序集不在文件系统中,而是在RAM中.
同样,上面列出了其他解决方案不起作用的原因:1.许多是4.0之前的版本,而且2.许多人依赖指向文件系统的".Load"方法.
答案2:我有一个汇编引用,因为它是由CSharpCodeProvider类生成的,所以如果你知道一种方法将它转换为字节数组,那将是完美的!
var provider = new CSharpCodeProvider(new Dictionary<String, String>
{ { "CompilerVersion", "v4.0" } });
var compilerparams = new CompilerParameters
{ GenerateExecutable = false, GenerateInMemory = true, };
var compilerResults = provider.CompileAssemblyFromSource(compilerparams,
string_Of_Code_From_A_User);
var instanceOfSomeClass = compilerResults.CompiledAssembly
.CreateInstance(className);
// The 'DoSomething' method can write to the file system and I don't like that!
instanceOfSomeClass.GetType().GetMethod("DoSomething")
.Invoke(instanceOfSomeClass, null);
Run Code Online (Sandbox Code Playgroud)
有两个原因:
Mik*_*keP 42
好的,首先要做的事情是:没有实际的方法可以使用CSharpCodeProvider完全在内存中动态编译C#源代码.有些方法似乎支持该功能,但由于C#编译器是无法在进程中运行的本机可执行文件,因此源字符串将保存到临时文件中,在该文件上调用编译器,然后生成的程序集为保存到磁盘,然后使用Assembly.Load为您加载.
其次,正如您所发现的,您应该能够在AppDomain中使用Compile方法来加载程序集并为其提供所需的权限.我遇到了同样不寻常的行为,经过大量挖掘后发现它是框架中的一个错误.我在MS Connect上提交了一份问题报告.
由于框架已经写入文件系统,因此解决方法是将程序集写入临时文件,然后根据需要加载.但是,当您加载它时,您需要在AppDomain中临时断言权限,因为您不允许访问文件系统.这是一个示例片段:
new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert();
var assembly = Assembly.LoadFile(assemblyPath);
CodeAccessPermission.RevertAssert();
Run Code Online (Sandbox Code Playgroud)
从那里,您可以使用程序集和反射来调用您的方法.请注意,此方法允许您在沙盒AppDomain之外提升编译过程,这在我看来是一个加号.
作为参考,这里是我的Sandbox类,它是为了便于在一个干净的单独AppDomain中启动脚本程序集,该AppDomain具有有限的权限,并且可以在必要时轻松卸载:
class Sandbox : MarshalByRefObject
{
const string BaseDirectory = "Untrusted";
const string DomainName = "Sandbox";
public Sandbox()
{
}
public static Sandbox Create()
{
var setup = new AppDomainSetup()
{
ApplicationBase = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BaseDirectory),
ApplicationName = DomainName,
DisallowBindingRedirects = true,
DisallowCodeDownload = true,
DisallowPublisherPolicy = true
};
var permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess));
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions,
typeof(Sandbox).Assembly.Evidence.GetHostEvidence<StrongName>());
return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap();
}
public string Execute(string assemblyPath, string scriptType, string method, params object[] parameters)
{
new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert();
var assembly = Assembly.LoadFile(assemblyPath);
CodeAccessPermission.RevertAssert();
Type type = assembly.GetType(scriptType);
if (type == null)
return null;
var instance = Activator.CreateInstance(type);
return string.Format("{0}", type.GetMethod(method).Invoke(instance, parameters));
}
}
Run Code Online (Sandbox Code Playgroud)
快速注意:如果您使用此方法为新AppDomain提供安全证据,则需要对程序集进行签名以赋予其强名称.
请注意,这在运行过程中工作正常,但是如果您真的想要一个防弹脚本环境,则需要更进一步,在单独的进程中隔离脚本,以确保执行恶意(或只是愚蠢)事情的脚本像堆栈溢出,fork炸弹和内存不足情况不会导致整个应用程序进程失效.如果您需要,我可以为您提供更多相关信息.
| 归档时间: |
|
| 查看次数: |
8477 次 |
| 最近记录: |