Share via


Como: Executar o código parcialmente confiável em um modo seguro

Modo seguro é a prática do código em execução em um ambiente de segurança restrito, que limita as permissões de acesso concedidas ao código. Por exemplo, se você tiver uma biblioteca gerenciada a partir de uma fonte que você não confia totalmente, você não deve executá-lo como totalmente confiável. Em vez disso, você deve colocar o código em uma proteção de limites de suas permissões para aqueles que você espera que ele precisa (por exemplo, Execution permissão).

Você também pode usar o modo seguro para testar o código que você distribuirá o que será executado em ambientes parcialmente confiáveis.

Um AppDomain é uma maneira eficaz de fornecer uma proteção para aplicativos gerenciados. Os domínios de aplicativo são usados para a execução de códigos parcialmente confiáveis têm permissões que definem os recursos protegidos que estão disponíveis quando em execução dentro do que AppDomain. O código executado dentro do AppDomain vinculado, as permissões associadas a AppDomain e pode acessar somente especificado recursos. O AppDomain também inclui um StrongName matriz que é usado para identificar os assemblies devem ser carregados como totalmente confiável. Isso permite que o criador de um AppDomain para iniciar um novo domínio no modo seguro que permite que os assemblies de auxiliar específico seja totalmente confiável. Outra opção para carregar assemblies totalmente confiáveis é colocá-los no cache de assembly global; No entanto, que irá carregar assemblies como totalmente confiável em todos os domínios de aplicativo criados no computador. A lista de forte nomes suporta um por-AppDomain decisão que fornece determinação mais restritivo.

Você pode usar o AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) sobrecarga do método para especificar o conjunto de permissões para aplicativos que são executados no modo seguro. Essa sobrecarga permite que você especifique o nível exato de code access security desejado. Assemblies são carregados para um AppDomain usando esse podem sobrecarga pode especificado conceder apenas o conjunto, ou pode ser totalmente confiável. O assembly é concedido confiança total, se ele estiver no cache global de assemblies ou listados na fullTrustAssemblies (a StrongName) matriz de parâmetro. Somente os assemblies conhecidos por ser totalmente confiáveis devem ser adicionados para o fullTrustAssemblies lista.

A sobrecarga tem a seguinte assinatura:

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

Os parâmetros para o CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) sobrecarga do método especifique o nome da AppDomain, a evidência para a AppDomain, o AppDomainSetup que identifica a base do aplicativo para o modo seguro, a permissão de objeto definido para usar, e os nomes de alta seguras para totalmente confiável assemblies.

Por motivos de segurança, a base do aplicativo especificado na info parâmetro não deve ser o aplicativo base para o aplicativo de hospedagem.

Para o grantSet parâmetro, você pode especificar um conjunto de permissões que você criou explicitamente ou uma permissão padrão conjunto criado pelo GetStandardSandbox método.

Ao contrário da maioria AppDomain for carregada, a evidência para a AppDomain (que é fornecido pela securityInfo parâmetro) não é usado para determinar a concessão definido para assemblies parcialmente confiável. Em vez disso, ele é especificado pelo independentemente de grantSet parâmetro. No entanto, a evidência pode ser usada para outros fins, tais como determinar o escopo do armazenamento isolado.

Para executar um aplicativo em um modo seguro

  1. Crie um conjunto de permissões para ser concedido ao aplicativo não confiável. A permissão mínima, você pode conceder é Execution permissão. Você também pode conceder permissões adicionais que você acha que podem ser seguras para código não confiável; Por exemplo, IsolatedStorageFilePermission. O código a seguir cria um novo conjunto de permissões com apenas Execution permissão.

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

    Como alternativa, você pode usar um conjunto de permissões nomeadas existente, como a Internet.

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

    O GetStandardSandbox método retorna um um Internet conjunto de permissões ou um LocalIntranet o conjunto de permissões dependendo da zona em evidência. GetStandardSandboxtambém constrói as permissões de identidade para alguns dos objetos evidências passados como referências.

  2. Assinar o assembly que contém a classe de hospedagem (chamado Sandboxer neste exemplo) que chama o código não confiável. Adicionar o StrongName usado para assinar o assembly para o StrongName matriz do fullTrustAssemblies parâmetro da CreateDomain chamada. A classe de hospedagem deve ser executado como totalmente confiável para permitir a execução do código parcialmente confiável ou oferecem serviços para o aplicativo de confiança parcial. Isso é como ler a StrongName de um assembly:

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

    .Assemblies do NET Framework, como mscorlib e System. dll não precisam ser adicionado à lista de confiança total, porque eles são carregados como totalmente confiável do cache global de assemblies.

  3. Inicializar o AppDomainSetup parâmetro do CreateDomain método. Com esse parâmetro, você pode controlar muitas das configurações da nova AppDomain. O ApplicationBase propriedade é uma configuração importante e deve ser diferente do ApplicationBase propriedade para o AppDomain do aplicativo de hospedagem. Se o ApplicationBase configurações são as mesmas, o aplicativo de confiança parcial pode obter o aplicativo de hospedagem (como totalmente confiável) uma exceção ao carregar define, assim, explorando o proprietário. Esta é outra razão por que não é recomendado um catch (exception). Configurando o aplicativo base do host de forma diferente a partir da base do aplicativo do aplicativo no modo seguro atenua o risco de explorações.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);
    
  4. Chamar o CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) a sobrecarga de método para criar o domínio de aplicativo usando os parâmetros que especificamos.

    A assinatura para este método é:

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

    Informações adicionais:

    • Esta é a única sobrecarga da CreateDomain método que usa um PermissionSet como um parâmetro e assim a sobrecarga de única que permite carregam um aplicativo em uma configuração de confiança parcial.

    • O evidence parâmetro não é usado para calcular um conjunto de permissões; ele é usado por outros recursos de identificação do.NET Framework.

    • Definindo a ApplicationBase propriedade da info parâmetro é obrigatório para essa sobrecarga.

    • O fullTrustAssemblies parâmetro tem o params palavra-chave, o que significa que não é necessário criar uma StrongName matriz. É permitido passar 0, 1 ou mais nomes de alta seguras como parâmetros.

    • O código para criar o domínio de aplicativo é:

    AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);
    
  5. Carregar o código para o modo seguro AppDomain que você criou. Isso pode ser feito de duas maneiras:

    O segundo método é preferível, porque torna mais fácil de passar parâmetros para o novo AppDomain instância. O CreateInstanceFrom método fornece dois recursos importantes:

    • Você pode usar uma base de código que aponta para um local que não contêm o seu assembly.

    • Você pode fazer a criação em um Assert para confiança total (PermissionState.Unrestricted), que permite que você criar uma instância de uma classe. crítica (Isso acontece sempre que seu conjunto possui sem marcações de transparência e é carregado como totalmente confiável). Portanto, você precisa tomar cuidado para criar somente o código que você confia com essa função, e recomendamos que você crie apenas as instâncias de classes totalmente confiáveis no novo domínio de aplicativo.

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

    Observe que, para criar uma instância de uma classe em um novo domínio, a classe tem que estender o MarshalByRefObject classe

    class Sandboxer:MarshalByRefObject
    
  6. Decodificar a nova instância de domínio em uma referência neste domínio. Esta referência é usada para executar o código não confiável.

    Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();
    
  7. Chamar o ExecuteUntrustedCode método na instância da Sandboxer classe que você acabou de criar.

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

    Essa chamada é executada no domínio de aplicativo no modo seguro, que tem permissões restritas.

    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é usado para obter um identificador de um método no assembly parcialmente confiável. O identificador pode ser usado para executar o código de uma maneira segura com o mínimo de permissões.

    No código anterior, observe o Assert para a permissão de confiança total antes de imprimir a SecurityException.

    new PermissionSet(PermissionState.Unrestricted)).Assert()
    

    A declaração de confiança total é usada para obter informações estendidas a partir de SecurityException. Sem o Assert, o ToString o método de SecurityException irá descobrir o que há código parcialmente confiável na pilha e restringirá as informações retornadas. Isso pode causar problemas de segurança, se o código parcialmente confiável poderia ler essas informações, mas o risco é reduzido, não concedendo UIPermission. A declaração de confiança total deve ser usada com moderação e somente quando você tiver certeza de que você não tiver permitindo código parcialmente confiável elevar a confiança total. Como regra, não chame código que não confia na mesma função e a chamada de uma declaração de confiança total. É recomendável sempre reverter assert, quando tiver terminado de usá-lo.

Exemplo

O exemplo a seguir implementa o procedimento na seção anterior. No exemplo, um projeto chamado Sandboxer um Visual Studio solução também contém um projeto chamado UntrustedCode, que implementa a classe UntrustedClass. Este cenário pressupõe que você baixou um assembly de biblioteca que contém um método que é esperado para retornar true ou false para indicar se o número fornecido é um número de Fibonacci. Em vez disso, o método tenta ler um arquivo do seu computador. O exemplo a seguir mostra o código não confiável.

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

A exemplo a seguir mostra a Sandboxer o código do aplicativo que executa o código não confiável.

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 também

Conceitos

Diretrizes para Codificação Segura