c# security .net-4.0 appdomain

c# - En.NET 4.0, ¿cómo ''sandbox'' un ensamblaje en memoria y ejecuto un método?



security .net-4.0 (1)

Bien, lo primero es lo primero: no hay una forma real de utilizar CSharpCodeProvider para hacer la compilación dinámica de la fuente C # completamente en la memoria. Existen métodos que parecen respaldar esa funcionalidad, pero dado que el compilador de C # es un ejecutable nativo que no puede ejecutarse en proceso, la cadena de origen se guarda en un archivo temporal, el compilador se invoca en ese archivo y luego el ensamblaje resultante es guardado en el disco y luego cargado para usted usando Assembly.Load.

En segundo lugar, como has descubierto, deberías poder utilizar el método de compilación dentro del dominio de la aplicación para cargar el conjunto y darle los permisos deseados. Me encontré con este mismo comportamiento inusual, y después de una gran cantidad de búsqueda descubrí que era un error en el marco. Archivé un informe de problema en MS Connect .

Dado que el framework ya está escribiendo en el sistema de archivos de todos modos, la solución alternativa es tener el ensamblado escrito en un archivo temporal y luego cargarlo según sea necesario. Sin embargo, cuando lo cargue, tendrá que afirmar temporalmente los permisos en el AppDomain, ya que no ha permitido el acceso al sistema de archivos. Aquí hay un fragmento de ejemplo de eso:

new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert(); var assembly = Assembly.LoadFile(assemblyPath); CodeAccessPermission.RevertAssert();

Desde allí puede usar el ensamblaje y la reflexión para invocar su método. Tenga en cuenta que este método le permite elevar el proceso de compilación fuera del AppDomain de espacio aislado, lo cual es una ventaja en mi opinión.

Como referencia, aquí está mi clase Sandbox creada para facilitar el lanzamiento de conjuntos de scripts en un bonito y limpio AppDomain separado que tiene permisos limitados y se puede descargar fácilmente cuando sea necesario:

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)); } }

Nota rápida: si utiliza este método para proporcionar pruebas de seguridad para el nuevo AppDomain, debe firmar su ensamblaje para darle un nombre seguro.

Tenga en cuenta que esto funciona bien cuando se ejecuta en proceso, pero si realmente desea un entorno de script a prueba de balas, necesita ir un paso más allá y aislar el script en un proceso separado para garantizar que los scripts que hacen cosas maliciosas (o simplemente estúpidas) como desbordamientos de pila, tenedor bombas y situaciones de falta de memoria no reducen todo el proceso de solicitud. Puedo darle más información sobre cómo hacerlo si lo necesita.

Esta es la razón por la cual se hizo esta pregunta: www.devplusplus.com/Tests/CSharp/Hello_World .

Si bien se hicieron preguntas similares anteriormente, las muchas respuestas en línea tienen varios problemas:

  1. Esto se debe hacer con el estilo ".Net 4.0", no con el modo heredado.
  2. El ensamblaje está en la memoria y solo estará en la memoria, no se puede escribir en el sistema de archivos.
  3. Me gustaría limitar todo acceso al sistema de archivos, a la red, etc.

Algo como esto:

var evidence = new Evidence(); evidence.AddHostEvidence(new Zone(SecurityZone.Internet)); var permissionSet = SecurityManager.GetStandardSandbox(evidence);

Hasta ahora, no puedo encontrar una manera de crear un AppDomain y cargar un ensamblado QUE NO ESTÉ EN EL SISTEMA DE ARCHIVOS , sino en la RAM.

Una vez más, las razones por las que las otras soluciones no funcionaron se identificaron anteriormente: 1. Muchas fueron para pre-4.0 y 2. Muchas se basaron en el método ".Load" que apunta al sistema de archivos.

Respuesta 2: Tengo una referencia de ensamblado debido a que está siendo generada por la clase CSharpCodeProvider , por lo que si conoce una forma de convertirlo en una matriz de bytes, ¡sería perfecto!

Código de muestra para mostrar el defecto de seguridad

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);

Entonces, ¿por qué no puedo simplemente guardar el ensamblaje en un archivo primero?

Por dos razones:

  1. Este código se encuentra en un servidor web compartido con permisos limitados para el sistema de archivos.
  2. Este código puede necesitar ejecutarse potencialmente miles de veces, y no quiero 1,000 dlls, ni siquiera temporalmente.