Dans .NET 4.0, comment puis-je “sandbox” un assemblage en mémoire et exécuter une méthode?

Voici la raison pour laquelle cette question a été posée: www.devplusplus.com/Tests/CSharp/Hello_World .

Bien que des questions similaires aient été posées auparavant, les nombreuses réponses en ligne comportent plusieurs problèmes:

  1. Cela doit être fait avec le style “.Net 4.0”, pas avec le mode hérité.
  2. L’assemblage est en mémoire et ne sera en mémoire que sur le système de fichiers.
  3. Je voudrais limiter tout access au système de fichiers, au réseau, etc.

Quelque chose comme ça:

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

Jusqu’à présent, je ne trouve pas de moyen de créer un AppDomain et de charger un assembly qui n’est pas sur le système de fichiers, mais plutôt dans la mémoire vive.

Encore une fois, les raisons pour lesquelles les autres solutions n’ont pas fonctionné sont identifiées ci-dessus: 1. Beaucoup étaient pour les versions antérieures à 4.0 et 2. Beaucoup se sont appuyées sur la méthode “.Load” pointant vers le système de fichiers.

Réponse 2: J’ai une référence d’assemblage car elle est générée par la classe CSharpCodeProvider , donc si vous connaissez un moyen de transformer cela en un tableau d’octets, ce serait parfait!

Exemple de code pour montrer le défaut de sécurité

 var provider = new CSharpCodeProvider(new Dictionary { { "ComstackrVersion", "v4.0" } }); var comstackrparams = new ComstackrParameters { GenerateExecutable = false, GenerateInMemory = true, }; var comstackrResults = provider.ComstackAssemblyFromSource(comstackrparams, ssortingng_Of_Code_From_A_User); var instanceOfSomeClass = comstackrResults.ComstackdAssembly .CreateInstance(className); // The 'DoSomething' method can write to the file system and I don't like that! instanceOfSomeClass.GetType().GetMethod("DoSomething") .Invoke(instanceOfSomeClass, null); 

Alors, pourquoi ne puis-je pas simplement sauvegarder l’assemblage dans un fichier?

Pour deux raisons:

  1. Ce code se trouve sur un serveur Web partagé avec des permissions limitées sur le système de fichiers lui-même.
  2. Ce code peut avoir besoin d’être exécuté des milliers de fois, et je ne veux pas 1000 dll, même temporairement.

OK, tout d’abord, il n’ya pas de moyen réel d’utiliser le CSharpCodeProvider pour faire la compilation dynamic de la source C # entièrement en mémoire. Certaines méthodes semblent prendre en charge cette fonctionnalité, mais le compilateur C # étant un exécutable natif qui ne peut pas s’exécuter en cours de traitement, la chaîne source est enregistrée dans un fichier temporaire, le compilateur est appelé sur ce fichier, puis l’assembly résultant est enregistré sur le disque, puis chargé pour vous en utilisant Assembly.Load.

Deuxièmement, comme vous l’avez découvert, vous devriez pouvoir utiliser la méthode Comstack depuis AppDomain pour charger l’assembly et lui donner les permissions souhaitées. J’ai rencontré ce même comportement inhabituel et après de nombreuses recherches, j’ai constaté que c’était un bug dans le framework. J’ai déposé un rapport de problème sur MS Connect .

Comme le framework écrit de toute façon sur le système de fichiers, la solution consiste à faire en sorte que l’assembly soit écrit dans un fichier temporaire, puis chargé selon les besoins. Toutefois, lorsque vous le chargez, vous devez autoriser temporairement les permissions dans AppDomain, car vous avez refusé l’access au système de fichiers. Voici un exemple de cet extrait:

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

De là, vous pouvez utiliser l’assemblage et la reflection pour appeler votre méthode. Notez que cette méthode vous permet de lever le processus de compilation en dehors de l’AppDomain en sandbox, ce qui est un plus à mon avis.

À titre de référence, voici ma classe Sandbox créée pour faciliter le lancement d’assemblys de script dans un AppDomain distinct bien conçu, doté d’permissions limitées et pouvant être facilement déchargé si nécessaire:

 class Sandbox : MarshalByRefObject { const ssortingng BaseDirectory = "Untrusted"; const ssortingng 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.RessortingctedMemberAccess)); permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions, typeof(Sandbox).Assembly.Evidence.GetHostEvidence()); return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap(); } public ssortingng Execute(ssortingng assemblyPath, ssortingng scriptType, ssortingng 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 ssortingng.Format("{0}", type.GetMethod(method).Invoke(instance, parameters)); } } 

Remarque rapide: si vous utilisez cette méthode pour fournir des preuves de sécurité pour le nouvel AppDomain, vous devez signer votre assembly pour lui donner un nom fort.

Notez que cela fonctionne bien lors de l’exécution, mais si vous voulez vraiment un environnement de script à l’épreuve des balles, vous devez aller plus loin et isoler le script dans un processus séparé pour garantir que les scripts malveillants (ou simplement stupides) comme les débordements de stacks, les bombes à fourche et les situations de mémoire insuffisante ne font pas tomber tout le processus de demande. Je peux vous donner plus d’informations si vous en avez besoin.