Cómo: Ejecutar código de confianza parcial en un recintoHow to: Run Partially Trusted Code in a Sandbox

Precaución

Seguridad de acceso del código (CAS) y código de confianza parcialCode Access Security (CAS) and Partially Trusted Code

.NET Framework proporciona seguridad de acceso del código (CAS), que es un mecanismo para el cumplimiento de los distintos niveles de confianza en diferentes códigos que se ejecutan en la misma aplicación.The .NET Framework provides a mechanism for the enforcement of varying levels of trust on different code running in the same application called Code Access Security (CAS).

Las CA no se admiten en .NET Core, .NET 5 o versiones posteriores. Las versiones de C# posteriores a 7,0 no admiten las CA.CAS is not supported in .NET Core, .NET 5, or later versions. CAS is not supported by versions of C# later than 7.0.

Las CA de .NET Framework no deben usarse como mecanismo para aplicar los límites de seguridad basados en el origen del código u otros aspectos de identidad.CAS in .NET Framework should not be used as a mechanism for enforcing security boundaries based on code origination or other identity aspects. Las CA y el código Security-Transparent no se admiten como límites de seguridad con código de confianza parcial, especialmente el código de origen desconocido.CAS and Security-Transparent Code are not supported as a security boundary with partially trusted code, especially code of unknown origin. Le aconsejamos que no cargue ni ejecute código de orígenes desconocidos sin contar con medidas de seguridad alternativas.We advise against loading and executing code of unknown origins without putting alternative security measures in place. .NET Framework no emitirá revisiones de seguridad para los ataques de elevación de privilegios que puedan detectarse en el espacio aislado de CAS..NET Framework will not issue security patches for any elevation-of-privilege exploits that might be discovered against the CAS sandbox.

Esta directiva se aplica a todas las versiones de .NET Framework, pero no se aplica a la versión de .NET Framework incluida en Silverlight.This policy applies to all versions of .NET Framework, but does not apply to the .NET Framework included in Silverlight.

El uso de espacios aislados consiste en ejecutar código en un entorno de seguridad restringido que limita los permisos de acceso concedidos al código.Sandboxing is the practice of running code in a restricted security environment, which limits the access permissions granted to the code. Por ejemplo, si tiene una biblioteca administrada procedente de un origen en el que no confía plenamente, no la ejecute como si fuese de plena confianza.For example, if you have a managed library from a source you do not completely trust, you should not run it as fully trusted. En su lugar, coloque el código en un espacio aislado que limite los permisos a los que considere necesarios (por ejemplo, el permiso Execution).Instead, you should place the code in a sandbox that limits its permissions to those that you expect it to need (for example, Execution permission).

También puede usar el espacio aislado para probar el código que va a distribuir y que se ejecutará en entornos de confianza parcial.You can also use sandboxing to test code you will be distributing that will run in partially trusted environments.

AppDomain es una forma eficaz de proporcionar un espacio aislado para las aplicaciones administradas.An AppDomain is an effective way of providing a sandbox for managed applications. Los dominios de aplicación que se usan para ejecutar código de confianza parcial tienen permisos que definen los recursos protegidos que están disponibles cuando se ejecuta dentro de ese AppDomain.Application domains that are used for running partially trusted code have permissions that define the protected resources that are available when running within that AppDomain. El código que se ejecuta dentro de AppDomain está limitado por los permisos asociados a AppDomain y tan solo puede tener acceso a los recursos especificados.Code that runs inside the AppDomain is bound by the permissions associated with the AppDomain and is allowed to access only the specified resources. AppDomain también incluye una matriz StrongName que se usa para identificar los ensamblados que cargan con plena confianza.The AppDomain also includes a StrongName array that is used to identify assemblies that are to be loaded as fully trusted. Esto permite que el creador de un AppDomain inicie un nuevo dominio en espacio aislado que permita confiar plenamente en ensamblados del asistente concretos.This enables the creator of an AppDomain to start a new sandboxed domain that allows specific helper assemblies to be fully trusted. Otra opción para cargar ensamblados como de plena confianza es colocarlos en la caché de ensamblados global. Sin embargo, eso cargará los ensamblados con plena confianza en todos los dominios de aplicación creados en ese equipo.Another option for loading assemblies as fully trusted is to place them in the global assembly cache; however, that will load assemblies as fully trusted in all application domains created on that computer. La lista de nombres seguros admite una decisión por AppDomain que proporciona una determinación más restrictiva.The list of strong names supports a per-AppDomain decision that provides more restrictive determination.

La sobrecarga del método AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) se puede usar para especificar el conjunto de permisos para las aplicaciones que se ejecutan en un espacio aislado.You can use the AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to specify the permission set for applications that run in a sandbox. Esta sobrecarga permite especificar el nivel exacto de seguridad de acceso del código que se desea.This overload enables you to specify the exact level of code access security you want. Los ensamblados que se cargan en AppDomain mediante esta sobrecarga pueden tener únicamente el conjunto de permisos especificado o pueden ser de plena confianza.Assemblies that are loaded into an AppDomain by using this overload can either have the specified grant set only, or can be fully trusted. Si el ensamblado está en la caché global de ensamblados o aparece enumerado en el parámetro de matrices fullTrustAssemblies (StrongName), se le concede confianza plena.The assembly is granted full trust if it is in the global assembly cache or listed in the fullTrustAssemblies (the StrongName) array parameter. Tan solo deben agregarse a la lista fullTrustAssemblies los ensamblados que se sabe que son de plena confianza.Only assemblies known to be fully trusted should be added to the fullTrustAssemblies list.

La sobrecarga tiene la siguiente firma:The overload has the following signature:

AppDomain.CreateDomain( string friendlyName,  
                        Evidence securityInfo,  
                        AppDomainSetup info,  
                        PermissionSet grantSet,  
                        params StrongName[] fullTrustAssemblies);  

Los parámetros de la sobrecarga del método CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) especifican el nombre de AppDomain, la evidencia de AppDomain, el objeto AppDomainSetup que identifica la base de la aplicación para el espacio aislado, el conjunto de permisos que se va a usar y los nombres seguros para los ensamblados de plena confianza.The parameters for the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload specify the name of the AppDomain, the evidence for the AppDomain, the AppDomainSetup object that identifies the application base for the sandbox, the permission set to use, and the strong names for fully trusted assemblies.

Por motivos de seguridad, la base de la aplicación especificada en el parámetro info no debe ser la base de la aplicación host.For security reasons, the application base specified in the info parameter should not be the application base for the hosting application.

Para el parámetro grantSet, puede especificar un conjunto de permisos que haya creado explícitamente o un conjunto de permisos estándar conjunto creado mediante el método GetStandardSandbox.For the grantSet parameter, you can specify either a permission set you have explicitly created, or a standard permission set created by the GetStandardSandbox method.

A diferencia de la mayoría de cargas de AppDomain, la evidencia para AppDomain (proporcionado por el parámetro securityInfo) no se usa para determinar el conjunto de permisos de los ensamblados de confianza parcial.Unlike most AppDomain loads, the evidence for the AppDomain (which is provided by the securityInfo parameter) is not used to determine the grant set for the partially trusted assemblies. En su lugar, se especifica por separado mediante el parámetro grantSet.Instead, it is independently specified by the grantSet parameter. Sin embargo, la evidencia puede usarse para otros fines como determinar el ámbito de almacenamiento aislado.However, the evidence can be used for other purposes such as determining the isolated storage scope.

Para ejecutar una aplicación en un espacio aisladoTo run an application in a sandbox

  1. Cree el conjunto de permisos que se concederán a la aplicación no confiable.Create the permission set to be granted to the untrusted application. El permiso mínimo que se puede conceder es Execution.The minimum permission you can grant is Execution permission. También puede conceder permisos adicionales si piensa que son seguros para el código no seguro, por ejemplo, IsolatedStorageFilePermission.You can also grant additional permissions you think might be safe for untrusted code; for example, IsolatedStorageFilePermission. El siguiente código crea un nuevo conjunto de permisos que contiene únicamente el permiso Execution.The following code creates a new permission set with only Execution permission.

    PermissionSet permSet = new PermissionSet(PermissionState.None);  
    permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));  
    

    Si lo prefiere, puede usar un conjunto de permisos con nombre existente, como Internet.Alternatively, you can use an existing named permission set, such as Internet.

    Evidence ev = new Evidence();  
    ev.AddHostEvidence(new Zone(SecurityZone.Internet));  
    PermissionSet internetPS = SecurityManager.GetStandardSandbox(ev);  
    

    El método GetStandardSandbox devolverá un conjunto de permisos Internet o un conjunto de permisos LocalIntranet según la zona de la evidencia.The GetStandardSandbox method returns either an Internet permission set or a LocalIntranet permission set depending on the zone in the evidence. GetStandardSandbox también construye permisos de identidad para algunos de los objetos de evidencia que se pasan como referencias.GetStandardSandbox also constructs identity permissions for some of the evidence objects passed as references.

  2. Firme el ensamblado que contiene la clase host (denominada Sandboxer en este ejemplo) que llama al código de confianza.Sign the assembly that contains the hosting class (named Sandboxer in this example) that calls the untrusted code. Agregue el StrongName usado para firmar el ensamblado a la matriz StrongName del parámetro fullTrustAssemblies de la llamada CreateDomain.Add the StrongName used to sign the assembly to the StrongName array of the fullTrustAssemblies parameter of the CreateDomain call. La clase host debe ejecutarse como de plena confianza para habilitar la ejecución del código de confianza parcial u ofrecer servicios a la aplicación de confianza parcial.The hosting class must run as fully trusted to enable the execution of the partial-trust code or to offer services to the partial-trust application. Así es como se lee el StrongName de un ensamblado:This is how you read the StrongName of an assembly:

    StrongName fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();  
    

    Los ensamblados de .NET Framework como mscorlib y System.dll no tienen que agregarse a la lista de plena confianza porque se cargan como de plena confianza desde la caché de ensamblados global..NET Framework assemblies such as mscorlib and System.dll do not have to be added to the full-trust list because they are loaded as fully trusted from the global assembly cache.

  3. Inicialice el parámetro AppDomainSetup del método CreateDomain.Initialize the AppDomainSetup parameter of the CreateDomain method. Con este parámetro, puede controlar muchas de las opciones del nuevo AppDomain.With this parameter, you can control many of the settings of the new AppDomain. La propiedad ApplicationBase es un valor importante y debe ser diferente de la propiedad ApplicationBase para el AppDomain de la aplicación host.The ApplicationBase property is an important setting, and should be different from the ApplicationBase property for the AppDomain of the hosting application. Si los valores de ApplicationBase son iguales, la aplicación de confianza parcial puede hacer que la aplicación host cargue (como de plena confianza) una excepción que define y, por tanto, aprovecharse de ella.If the ApplicationBase settings are the same, the partial-trust application can get the hosting application to load (as fully trusted) an exception it defines, thus exploiting it. Este es otro motivo por el que no se recomienda un bloque catch (excepción).This is another reason why a catch (exception) is not recommended. El riesgo de ataques se reduce si la base de la aplicación del host y la base de la aplicación de la aplicación en espacio aislado se configuran de forma diferente.Setting the application base of the host differently from the application base of the sandboxed application mitigates the risk of exploits.

    AppDomainSetup adSetup = new AppDomainSetup();  
    adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);  
    
  4. Llame a la sobrecarga del método CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) para crear el dominio de aplicación usando los parámetros especificados.Call the CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) method overload to create the application domain using the parameters we have specified.

    La firma de este método es:The signature for this method is:

    public static AppDomain CreateDomain(string friendlyName,
        Evidence securityInfo, AppDomainSetup info, PermissionSet grantSet,
        params StrongName[] fullTrustAssemblies)  
    

    Información adicional:Additional information:

    • Esta es la única sobrecarga del método CreateDomain que toma PermissionSet como un parámetro y, por lo tanto, la única sobrecarga que permite cargar una aplicación en un entorno de confianza parcial.This is the only overload of the CreateDomain method that takes a PermissionSet as a parameter, and thus the only overload that lets you load an application in a partial-trust setting.

    • El parámetro evidence no se usa para calcular un conjunto de permisos, sino que se usa para identificar otras características de .NET Framework.The evidence parameter is not used to calculate a permission set; it is used for identification by other features of the .NET Framework.

    • En esta sobrecarga es obligatorio establecer la propiedad ApplicationBase del parámetro info.Setting the ApplicationBase property of the info parameter is mandatory for this overload.

    • El parámetro fullTrustAssemblies tiene la palabra clave params, lo que significa que no es necesario crear una matriz StrongName.The fullTrustAssemblies parameter has the params keyword, which means that it is not necessary to create a StrongName array. Se permite pasar 0, 1 o más nombres seguros como parámetros.Passing 0, 1, or more strong names as parameters is allowed.

    • El código para crear el dominio de aplicación es:The code to create the application domain is:

    AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);  
    
  5. Cargar el código en el espacio aislado AppDomain que creó.Load the code into the sandboxing AppDomain that you created. Esto puede hacerse de dos maneras:This can be done in two ways:

    El segundo método es preferible, porque es más fácil pasar parámetros a la nueva instancia AppDomain.The second method is preferable, because it makes it easier to pass parameters to the new AppDomain instance. El método CreateInstanceFrom proporciona dos características importantes:The CreateInstanceFrom method provides two important features:

    • Puede usar una base de código que apunte a una ubicación que no contenga su ensamblado.You can use a code base that points to a location that does not contain your assembly.

    • Puede realizar la creación en un Assert de plena confianza (PermissionState.Unrestricted), lo que le permite crear una instancia de una clase crítica.You can do the creation under an Assert for full-trust (PermissionState.Unrestricted), which enables you to create an instance of a critical class. (Esto sucede cuando el ensamblado no tiene marcas de transparencia y se carga como de plena confianza). Por lo tanto, debe tener cuidado de crear solo código en el que confíe con esta función y se recomienda crear solo instancias de clases de plena confianza en el nuevo dominio de aplicación.(This happens whenever your assembly has no transparency markings and is loaded as fully trusted.) Therefore, you have to be careful to create only code that you trust with this function, and we recommend that you create only instances of fully trusted classes in the new application domain.

    ObjectHandle handle = Activator.CreateInstanceFrom(  
    newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,  
           typeof(Sandboxer).FullName );  
    

    Para crear una instancia de una clase en un dominio nuevo, la clase debe extender la MarshalByRefObject clase.To create an instance of a class in a new domain, the class must extend the MarshalByRefObject class.

    class Sandboxer:MarshalByRefObject  
    
  6. Desempaquete la nueva instancia del dominio en una referencia en este dominio.Unwrap the new domain instance into a reference in this domain. Esta referencia se usa para ejecutar el código no confiable.This reference is used to execute the untrusted code.

    Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();  
    
  7. Llame al método ExecuteUntrustedCode en la instancia de la clase Sandboxer que acaba de crear.Call the ExecuteUntrustedCode method in the instance of the Sandboxer class you just created.

    newDomainInstance.ExecuteUntrustedCode(untrustedAssembly, untrustedClass, entryPoint, parameters);  
    

    Esta llamada se ejecuta en el dominio de la aplicación en espacio aislado, que tiene permisos restringidos.This call is executed in the sandboxed application domain, which has restricted permissions.

    public void ExecuteUntrustedCode(string assemblyName, string typeName, string entryPoint, Object[] parameters)  
    {  
        //Load the MethodInfo for a method in the new assembly. This might be a method you know, or
        //you can use Assembly.EntryPoint to get to the entry point in an executable.  
        MethodInfo target = Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);  
        try  
        {  
            // Invoke the method.  
            target.Invoke(null, parameters);  
        }  
        catch (Exception ex)  
        {  
        //When information is obtained from a SecurityException extra information is provided if it is
        //accessed in full-trust.  
            new PermissionSet(PermissionState.Unrestricted).Assert();  
            Console.WriteLine("SecurityException caught:\n{0}", ex.ToString());  
            CodeAccessPermission.RevertAssert();  
            Console.ReadLine();  
        }  
    }  
    

    System.Reflection se usa para obtener el identificador de un método en el ensamblado de confianza parcial.System.Reflection is used to get a handle of a method in the partially trusted assembly. El identificador puede usarse para ejecutar código de forma segura con permisos mínimos.The handle can be used to execute code in a safe way with minimum permissions.

    En el código anterior, observe Assert para el permiso de plena confianza antes de imprimir SecurityException.In the previous code, note the Assert for the full-trust permission before printing the SecurityException.

    new PermissionSet(PermissionState.Unrestricted).Assert()  
    

    La aserción de plena confianza se usa para obtener la información ampliada de SecurityException.The full-trust assert is used to obtain extended information from the SecurityException. Sin Assert, el método ToString de SecurityException detectará que hay código de confianza parcial en la pila y restringirá la información devuelta.Without the Assert, the ToString method of SecurityException will discover that there is partially trusted code on the stack and will restrict the information returned. Esto podría provocar problemas de seguridad si el código de confianza parcial llega a leer esa información, pero el riesgo se mitiga al no conceder UIPermission.This could cause security issues if the partial-trust code could read that information, but the risk is mitigated by not granting UIPermission. La aserción de plena confianza debe usarse con moderación y solo cuando si se está seguro de que no se permite al código de confianza parcial elevarse a plena confianza.The full-trust assert should be used sparingly and only when you are sure that you are not allowing partial-trust code to elevate to full trust. Como norma general, no llame a un código en el que no confía en la misma función y tras invocar una aserción de plena confianza.As a rule, do not call code you do not trust in the same function and after you called an assert for full trust. Le recomendamos que revierta siempre la aserción cuando acabe de usarla.It is good practice to always revert the assert when you have finished using it.

EjemploExample

En el ejemplo siguiente se implementa el procedimiento de la sección anterior.The following example implements the procedure in the previous section. En el ejemplo, un proyecto denominado Sandboxer en una solución de Visual Studio también contiene un proyecto denominado UntrustedCode que implementa la clase UntrustedClass.In the example, a project named Sandboxer in a Visual Studio solution also contains a project named UntrustedCode, which implements the class UntrustedClass. En este escenario se supone que ha descargado un ensamblado de biblioteca que contiene un método que debe devolver true o false para indicar si el número proporcionado es un número de Fibonacci.This scenario assumes that you have downloaded a library assembly containing a method that is expected to return true or false to indicate whether the number you provided is a Fibonacci number. En su lugar, el método intenta leer un archivo de su equipo.Instead, the method attempts to read a file from your computer. En el ejemplo siguiente se muestra el código no confiable.The following example shows the untrusted code.

using System;  
using System.IO;  
namespace UntrustedCode  
{  
    public class UntrustedClass  
    {  
        // Pretend to be a method checking if a number is a Fibonacci  
        // but which actually attempts to read a file.  
        public static bool IsFibonacci(int number)  
        {  
           File.ReadAllText("C:\\Temp\\file.txt");  
           return false;  
        }  
    }  
}  

En el ejemplo siguiente se muestra el código de la aplicación Sandboxer que ejecuta el código no confiable.The following example shows the Sandboxer application code that executes the untrusted code.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.IO;  
using System.Security;  
using System.Security.Policy;  
using System.Security.Permissions;  
using System.Reflection;  
using System.Runtime.Remoting;  
  
//The Sandboxer class needs to derive from MarshalByRefObject so that we can create it in another
// AppDomain and refer to it from the default AppDomain.  
class Sandboxer : MarshalByRefObject  
{  
    const string pathToUntrusted = @"..\..\..\UntrustedCode\bin\Debug";  
    const string untrustedAssembly = "UntrustedCode";  
    const string untrustedClass = "UntrustedCode.UntrustedClass";  
    const string entryPoint = "IsFibonacci";  
    private static Object[] parameters = { 45 };  
    static void Main()  
    {  
        //Setting the AppDomainSetup. It is very important to set the ApplicationBase to a folder
        //other than the one in which the sandboxer resides.  
        AppDomainSetup adSetup = new AppDomainSetup();  
        adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);  
  
        //Setting the permissions for the AppDomain. We give the permission to execute and to
        //read/discover the location where the untrusted code is loaded.  
        PermissionSet permSet = new PermissionSet(PermissionState.None);  
        permSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));  
  
        //We want the sandboxer assembly's strong name, so that we can add it to the full trust list.  
        StrongName fullTrustAssembly = typeof(Sandboxer).Assembly.Evidence.GetHostEvidence<StrongName>();  
  
        //Now we have everything we need to create the AppDomain, so let's create it.  
        AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);  
  
        //Use CreateInstanceFrom to load an instance of the Sandboxer class into the  
        //new AppDomain.
        ObjectHandle handle = Activator.CreateInstanceFrom(  
            newDomain, typeof(Sandboxer).Assembly.ManifestModule.FullyQualifiedName,  
            typeof(Sandboxer).FullName  
            );  
        //Unwrap the new domain instance into a reference in this domain and use it to execute the
        //untrusted code.  
        Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();  
        newDomainInstance.ExecuteUntrustedCode(untrustedAssembly, untrustedClass, entryPoint, parameters);  
    }  
    public void ExecuteUntrustedCode(string assemblyName, string typeName, string entryPoint, Object[] parameters)  
    {  
        //Load the MethodInfo for a method in the new Assembly. This might be a method you know, or
        //you can use Assembly.EntryPoint to get to the main function in an executable.  
        MethodInfo target = Assembly.Load(assemblyName).GetType(typeName).GetMethod(entryPoint);  
        try  
        {  
            //Now invoke the method.  
            bool retVal = (bool)target.Invoke(null, parameters);  
        }  
        catch (Exception ex)  
        {  
            // When we print informations from a SecurityException extra information can be printed if we are
            //calling it with a full-trust stack.  
            new PermissionSet(PermissionState.Unrestricted).Assert();  
            Console.WriteLine("SecurityException caught:\n{0}", ex.ToString());  
            CodeAccessPermission.RevertAssert();  
            Console.ReadLine();  
        }  
    }  
}  

Consulte tambiénSee also