Sdílet prostřednictvím


Postupy: Spustit částečně důvěryhodný kód v izolovaném prostoru

Prostorová izolace postup spuštění kódu v prostředí omezeného zabezpečení omezuje přístupová oprávnění udělená kód. Například pokud máte spravovanou knihovny ze zcela důvěryhodného zdroje, nespouštět ho jako plně důvěryhodné. Místo toho by v karanténě, která omezuje jeho oprávnění, které je třeba očekávat umístit kód (například Execution oprávnění).

Prostorová izolace také umožňuje testovat kód, který bude distribuce a bude spuštěn v prostředí částečně důvěryhodných.

AppDomain Je účinný způsob poskytování karantény pro spravované aplikace. Aplikační domény pro spuštění částečně důvěryhodného kódu mají oprávnění, které definují chráněným prostředkům, které jsou k dispozici při spuštění v tomto AppDomain. Kód, který bude spuštěn uvnitř AppDomain je vázán oprávněními přidruženými s AppDomain a má povolení získat přístup pouze pro dané prostředky. AppDomain zahrnuje rovněž pole StrongName, které slouží k identifikaci sestavení, které mají být načteny jako plně důvěryhodné. To umožňuje autorovi AppDomain Spustit novou doménu uzavřených apletů, která umožňuje být plně důvěryhodné sestavení zvláštní pomocné. Jiná možnost pro načtení sestavení jako plně důvěryhodných, je umístit je do globální mezipaměti sestavení (GAC); toto však načte sestavení jako plně důvěryhodné ve všech doménách aplikací vytvořených v tomto počítači. Seznam silných názvů podporujících AppDomain rozhodnutí, které poskytující více omezující stanovení.

Můžete použít přetížení metody AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) k určení sady oprávnění pro aplikace spuštěné v izolovaném prostoru. Toto přetížení umožňuje určit přesnou úroveň zabezpečení přístupu ke kódu, které chcete. Sestavení, které jsou načteny do AppDomain pomocí tohoto přetížení, mohou mít buď zadaná udělení pouze nastavena, nebo mohou být plně důvěryhodná. Sestavení uděleno, pokud globální mezipaměť sestavení (GAC) úplný vztah důvěryhodnosti nebo uvedeny v fullTrustAssemblies ( StrongName) pole parametru. Pouze známým plně důvěryhodné sestavení do fullTrustAssemblies seznamu.

Přetížení má následující zápis:

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

Parametry CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) přetížení metody zadat název AppDomain, důkazy AppDomain, AppDomainSetup objekt, který identifikuje základní aplikace pro karanténu oprávnění nastavena, a silných názvů pro plně důvěryhodných sestavení.

Z bezpečnostních důvodů podle základní aplikace info parametr by měl být aplikace základ pro hostitelské aplikace.

Pro grantSet parametr zadáte výslovně vytvořené sady oprávnění nebo oprávnění standardní sada vytvořené GetStandardSandbox metody.

Na rozdíl od většiny AppDomain načte důkazy AppDomain (poskytnutými securityInfo parametr) slouží k určení grantu pro částečně důvěryhodných sestavení. Místo toho je nezávisle určena parametrem grantSet. Legitimace však lze použít pro jiné účely, jako je například určení rozsahu izolovaného úložiště.

Spuštění aplikace v izolovaném prostoru

  1. Vytvořte sadu oprávnění, která má být poskytovaná nedůvěryhodné aplikaci. Minimální oprávnění, které můžete udělit je oprávnění Execution. Můžete také udělit další oprávnění, u kterých si myslíte, že jsou pravděpodobně bezpečné pro nedůvěryhodný kód; například IsolatedStorageFilePermission. Následující kód vytvoří novou sadu oprávnění pouze s oprávněním Execution.

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

    Alternativně můžete použít existující sadu pojmenovaných oprávnění, jako je například Internet.

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

    Metoda GetStandardSandbox vrátí buď sadu oprávnění Internet nebo sadu oprávnění LocalIntranet v závislosti na zóně stanovené legitimace. GetStandardSandbox také vytvoří oprávnění identity pro některé objekty legitimace předané jako odkazy.

  2. Podepište sestavení, které obsahuje hostovací třídu (s názvem Sandboxer v tomto příkladu), která volá nedůvěryhodný kód. Přidejte StrongName použitý k podepsání sestavení, které má pole StrongName parametr fullTrustAssemblies volání CreateDomain. Hostující třída musí být spuštěna jako plně důvěryhodná, chcete-li povolit provádění kódu částečně důvěryhodného kódu nebo nabídnout služby částečně důvěryhodné aplikaci. Zde je, jak přečíst StrongName sestavení:

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

    Sestavení rozhraní .NET framework, například jako mscorlib a System.dll, nemusíte přidávat do seznamu plné důvěryhodnosti, protože jsou načteny jako plně důvěryhodné z globální mezipaměti sestavení (GAC).

  3. Inicializujte parametr AppDomainSetup metody CreateDomain. S tímto parametrem můžete řídit mnoho nastavení nové AppDomain. Vlastnost ApplicationBase je důležité nastavení a mělo by být odlišné od vlastnosti ApplicationBase pro AppDomain hostitelské aplikace. Pokud ApplicationBase nastavení jsou stejná, částečné důvěryhodnosti aplikace může získat hostitelská aplikace (jako plně důvěryhodné) zavést výjimku, kterou definuje, tedy jeho využívání Toto je dalším důvodem, proč není doporučeno catch (výjimka). Nastavení základu aplikace hostitele odlišně od základu aplikace v izolovaném úložišti snižuje riziko zneužití.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = Path.GetFullPath(pathToUntrusted);
    
  4. Volejte přetížení metody CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) k vytvoření0 domény aplikace pomocí parametrů, které jsme určili.

    Zápis pro tuto metodu je:

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

    Další informace:

    • Toto je jediné přetížení metody CreateDomain, která přijímá PermissionSet jako parametr a tedy jediné přetížení, které umožňuje načtení aplikace v nastavení částečné důvěryhodnosti.

    • Parametr evidence neslouží k výpočtu sady oprávnění; je používán pro identifikaci dalších funkcí rozhraní .NET Framework.

    • Nastavení vlastnosti ApplicationBase parametru info je povinné pro toto přetížení.

    • Parametr fullTrustAssemblies má klíčové slovo params, což znamená, že není nutné vytvořit pole StrongName. Je povoleno předávání 0, 1, nebo více silných názvů jako parametry.

    • Kód, kterým chcete vytvořit doménu aplikace, je:

    AppDomain newDomain = AppDomain.CreateDomain("Sandbox", null, adSetup, permSet, fullTrustAssembly);
    
  5. Načtěte kód do sandboxing AppDomain, kterou jste vytvořili. To lze udělat dvěma způsoby:

    Druhá metoda je vhodnější, protože usnadňuje předat parametry nové instanci AppDomain. Metoda CreateInstanceFrom obsahuje dvě důležité funkce:

    • Můžete použít základ kódu, který odkazuje na umístění, které neobsahuje vaše sestavení.

    • Můžete provést vytvoření v rámci Assert pro plnou důvěryhodnost (PermissionState.Unrestricted), což vám umožňuje vytvořit instanci kritické třídy. (Tato situace nastane vždy, když vaše sestavení nemá žádné označení transparentnosti a je načteno jako plně důvěryhodné.) Proto je nutné pomocí této funkce pečlivě vytvořit pouze kód, který považujete za důvěryhodný a doporučujeme vytvořit pouze instance tříd plně důvěryhodných v nové doméně aplikace.

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

    Všimněte si, že chcete-li vytvořit instanci třídy v nové doméně, třída musí rozšířit trídu MarshalByRefObject

    class Sandboxer:MarshalByRefObject
    
  6. Rozviňte novou instanci domény do odkazu v této doméně. Tento odkaz se používá k provedení nedůvěryhodného kódu.

    Sandboxer newDomainInstance = (Sandboxer) handle.Unwrap();
    
  7. Volání ExecuteUntrustedCode metodu instance Sandboxer třídy, které jste právě vytvořili.

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

    Toto volání je spuštěno v doméně aplikace v izolovaném úložišti, která má omezená oprávnění.

    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 slouží k získání popisovače metody v částečně důvěryhodném sestavení. Popisovač lze použít k provedení kódu bezpečným způsobem s minimálními oprávněními.

    V předchozím kódu nezapomeňte Assert oprávnění plně důvěryhodné před tiskem SecurityException.

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

    Plně důvěryhodné assert se používá k získání rozšířených informací z SecurityException. Bez Assert, metoda ToString SecurityException zjistí, že je zde částečně důvěryhodný kód v zásobníku a omezí vrácené informace. Pokud kód částečné důvěryhodnosti nelze číst informace, ale riziko je zmírnila udělením není to může způsobit problémy zabezpečení UIPermission. Požadavek plné důvěryhodnosti by měl být používán zřídka a pouze v případě, že se ujistíte, že nepovolujete částečně důvěryhodný kód ke zvýšení na úplný vztah důvěryhodnosti. Zpravidla Nevolejte důvěryhodného kódu tutéž funkci a po assert názvem pro úplný vztah důvěryhodnosti. Je vhodné vždy vrátit assert po jeho použití.

Příklad

Následující příklad implementuje proceduru v předchozím oddíle. V příkladu projekt s názvem Sandboxer v řešení sady Visual Studio obsahuje také projekt s názvem UntrustedCode, který implementuje třídu UntrustedClass. Tento scénář předpokládá stáhli sestavení knihovny obsahující metodu, která zpět true nebo false označující, zda číslo poskytnuté je Fibonacci číslo. Místo toho se metoda pokusí přečíst soubor z vašeho počítače. Následující příklad ukazuje nedůvěryhodný kód.

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

Následující příklad ukazuje kód aplikace Sandboxer, který provede nedůvěryhodný kód.

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

Viz také

Koncepty

Pokyny pro zabezpečené kódování