Exportar (0) Imprimir
Expandir Tudo
Este artigo foi traduzido por máquina. Coloque o ponteiro do mouse sobre as frases do artigo para ver o texto original. Mais informações.
Tradução
Original

Como executar código parcialmente confiável em uma área restrita

Restrição de área é a prática de executar código em um ambiente de segurança restrito, o que limita as permissões de acesso concedidas ao código. Por exemplo, se você tiver uma biblioteca gerenciada de uma fonte não completamente confiável, não deve executá-la como totalmente confiável. Em vez disso, você deve colocar o código em uma área restrita que limite suas permissões àquelas que você espera que ele precisa (por exemplo, a permissão Execution).

Você também pode usar a área restrita ao código de teste que você estará distribuindo que será executado em ambientes parcialmente confiáveis.

Um AppDomain é uma forma eficiente de fornecer uma área restrita para aplicativos gerenciados. Os Domínios de Aplicativo usados executando o código parcialmente confiável têm as permissões que definem recursos protegidos disponíveis para executar dentro desse AppDomain. O código executado dentro do AppDomain é associado pelas permissões associadas com o AppDomain e podem acessar somente os recursos especificados. O AppDomain também inclui uma matriz StrongName, usada para identificar os assemblies que devem ser carregados como totalmente confiáveis. Isso permite que o criador de um AppDomain inicie um novo domínio na área restrita que permite que assemblies auxiliares específicos sejam totalmente confiáveis. Outra opção para carregar assemblies como totalmente confiável é colocá-los na cache de assemblies global; no entanto, isso irá carregar assemblies como totalmente confiável nos domínios de aplicativos criados no computador. A lista de nomes fortes oferece suporte à decisão de AppDomain que fornece uma decisão mais restritiva.

Você pode usar a sobrecarga do método AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) para especificar o conjunto de permissões para aplicativos executados em uma área restrita. Essa sobrecarga permite que você especifique o nível exato de segurança de acesso ao código que você deseja. Assemblies carregadas em um AppDomain usando essa sobrecarga podem ter apenas a concessão especificada definida ou podem ser totalmente confiáveis. O assembly é concedido com confiança total se estiver no cache de assembly global ou listado no parâmetro de matriz fullTrustAssemblies (StrongName). Somente os assemblies conhecidos por serem totalmente confiáveis devem ser adicionados à lista fullTrustAssemblies .

A sobrecarga possui a seguinte assinatura:

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

Os parâmetros para a sobrecarga do método CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) especificam o nome AppDomain, a evidência para o AppDomain, o objeto de AppDomainSetup que identifica a base do aplicativo para a área restrita, o conjunto de permissões de uso, e os nomes fortes para assemblies totalmente confiáveis.

Por razões de segurança, a base do aplicativo especificado no parâmetro info não deve ser a base do aplicativo para o aplicativo hospedeiro.

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

Ao contrário da maioria dos carregamentos de AppDomain , a evidência para AppDomain (que é fornecida pelo parâmetro de securityInfo ) não é usada para determinar o conjunto de concessão de assemblies parcialmente confiáveis. Em vez disso, ele é especificado independentemente pelo parâmetro grantSet. No entanto, a evidência pode ser usada para outros fins tais como determinar o escopo de armazenamento isolado.

Para executar um aplicativo em uma área restrita

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

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

    Como alternativa, é possível 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 método de GetStandardSandbox retorna um conjunto de permissões de Internet ou um conjunto de permissões de LocalIntranet, dependendo da zona da evidência. GetStandardSandbox também constrói permissões de identidade para alguns dos objetos de evidência passados como referências.

  2. Assine o assembly que contém a classe de hospedagem (chamada Sandboxer neste exemplo) que chama o código não confiável. Adicione o StrongName usado para assinar o assembly à matriz StrongName do parâmetro fullTrustAssemblies da chamada CreateDomain. A classe de hospedagem deve ser executada como totalmente confiável para ativar a execução do código parcialmente confiável ou para oferecer serviços para o aplicativo parcialmente confiável. É assim que você lê o StrongName de um assembly:

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

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

  3. Inicializar o parâmetro AppDomainSetup do método CreateDomain. Com esse parâmetro, você pode controlar muitas das configurações do novo AppDomain. A propriedade ApplicationBase é uma configuração importante, e deve ser diferente da propriedade ApplicationBase para AppDomain do aplicativo hospedeiro. Se as configurações de ApplicationBase são as mesmas, o aplicativo de confiança parcial pode obter o aplicativo de hospedagem para carregar (como totalmente confiável) uma exceção que define, portanto, explorá-lo. Esse é outro motivo pelo qual uma captura (exceção) não é recomendada. Definir a base de aplicativos do host de maneira diferente da base de aplicativos do aplicativo em área restrita mitiga o risco de scripts maliciosos.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);
    

  4. Chame uma sobrecarga de método CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) para criar o domínio de aplicativo usando parâmetros especificados.

    A assinatura para este método é:

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

    Informações adicionais:

    • Essa é a única sobrecarga do método CreateDomain que leva PermissionSet como um parâmetro, logo, a única sobrecarga que permite que você carregue um aplicativo em uma configuração parcialmente confiável.

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

    • É obrigatório definir a propriedade ApplicationBase do parâmetro info para essa sobrecarga.

    • O parâmetro fullTrustAssemblies tem a palavra-chave params, o que significa que não é necessário criar uma matriz de StrongName . É permitido passar 0, 1 ou nomes mais fortes 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 na área restrita AppDomain que você criou. Isso pode ser feito de duas maneiras:

    O segundo método é preferível, porque torna mais fácil a passagem dos parâmetros para a nova instância AppDomain . O método CreateInstanceFrom fornece dois importantes recursos:

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

    • Você pode fazer a criação em um Assert para confiança total (PermissionState.Unrestricted), o que permite que você crie uma instância de uma classe crítica. (Isso ocorre sempre que seu assembly não tem nenhuma marcação de transparência e é carregado como totalmente confiável.) Portanto, você precisa ter cuidado para criar somente um código ao qual você confie essa função, e nós recomendamos que você crie apenas instâncias de classes totalmente confiáveis no domínio do novo 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 precisa estender a classe MarshalByRefObject

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

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

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

    Essa chamada é executada no domínio do aplicativo da área restrita, que possui 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 permissões mínimas.

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

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

    A declaração de totalmente confiável é usada para obter informações estendidas do SecurityException. Sem o Assert, o método ToString de SecurityException descobrirá que há um código parcialmente confiável na pilha e restringirá a informação retornada. Isso poderia causar problemas de segurança se o código parcialmente confiável pudesse ler essa informação, mas o risco é abrandado não concedendo UIPermission. A declaração de totalmente confiável deve ser usada com moderação, e somente quando você tiver certeza de que você não está permitindo que um código parcialmente confiável seja elevado para totalmente confiável. Em geral, não chame o código que você não confia na mesma função e depois de chamar uma declaração para confiança total. É uma boa prática sempre reverter a declaração quando você tiver terminado de usá-lo.

O exemplo a seguir implementa o procedimento na seção anterior. No exemplo, um projeto chamado Sandboxer em uma solução do Visual Studio também contém um projeto chamado UntrustedCode, que implementa a classe UntrustedClass. Esse cenário pressupõe que você baixou um conjunto de módulos (assembly) que contém um método que se espera retornar true ou false indicar se o número que você forneceu é 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;
        }
    }
}

O exemplo a seguir mostra o código do aplicativo Sandboxer 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();
        }
    }
}

Contribuições da comunidade

ADICIONAR
Mostrar:
© 2014 Microsoft