In.NET 4.0, jak "sandbox" montażu w pamięci i wykonać metodę?

Oto powód, dla którego zadano to pytanie: www.devplusplus.com/Tests/CSharp/Hello_World .

Podczas gdy podobne pytania zadawano wcześniej, wiele odpowiedzi online ma kilka problemów:

  1. należy to zrobić w stylu". Net 4.0", a nie w trybie legacy.
  2. Zgromadzenie jest w pamięci i będzie tylko w pamięci, nie może być zapisane do systemu plików.
  3. chciałbym ograniczyć cały dostęp do systemu plików, sieci, itd.

Coś takiego:

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

Na razie nie mogę znaleźć sposobu na stworzenie AppDomain i załadowanie assembly , który nie jest w systemie plików , ale raczej w pamięci RAM.

Ponownie, powody, dla których inne rozwiązania nie działały są wymienione powyżej: 1. Wiele było dla pre-4.0 i 2. Wielu oparło się na".Load " metoda wskazująca na system plików.

Odpowiedź 2: mam odniesienie do assembly, ponieważ jest generowane przez klasę CSharpCodeProvider, więc jeśli znasz sposób aby przekształcić to w tablicę bajtów, byłoby to idealne!

Przykładowy kod pokazujący wadę bezpieczeństwa

var provider = new CSharpCodeProvider(new Dictionary<String, String>
    { { "CompilerVersion", "v4.0" } });

var compilerparams = new CompilerParameters
    { GenerateExecutable = false, GenerateInMemory = true, };

var compilerResults = provider.CompileAssemblyFromSource(compilerparams,
    string_Of_Code_From_A_User);

var instanceOfSomeClass = compilerResults.CompiledAssembly
    .CreateInstance(className);

// The 'DoSomething' method can write to the file system and I don't like that!
instanceOfSomeClass.GetType().GetMethod("DoSomething")
    .Invoke(instanceOfSomeClass, null);

Więc dlaczego nie mogę najpierw zapisać zestawu do pliku?

Z dwóch powodów:

  1. Ten kod znajduje się na współdzielonym serwerze WWW z ograniczonymi uprawnieniami do samego systemu plików.
  2. Ten kod może być uruchamiany potencjalnie tysiące razy, i nie chcę 1000 DLL, nawet tymczasowo.
Author: Peter O., 2011-05-13

1 answers

OK, po pierwsze: nie ma rzeczywistego sposobu na użycie CSharpCodeProvider do dynamicznej kompilacji C# source w całości w pamięci. Istnieją metody, które wydają się wspierać tę funkcjonalność, ale ponieważ kompilator C# jest natywnym programem wykonywalnym, który nie może być uruchomiony w trakcie procesu, łańcuch źródłowy jest zapisywany do pliku tymczasowego, kompilator jest wywoływany na tym pliku, a następnie Wynikowy zestaw jest zapisywany na dysku, a następnie ładowany za pomocą Assembly.Ładuj.

Po drugie, jak już wykryte, powinieneś być w stanie użyć metody kompilacji z poziomu AppDomain, aby załadować zespół i nadać mu pożądane uprawnienia. Natknąłem się na to samo niezwykłe zachowanie i po wielu Kopaniach okazało się, że był to błąd w ramach. Złożyłem raport o problemie na MS Connect .

Ponieważ framework i tak już zapisuje do systemu plików, obejściem jest zapisanie złożenia do pliku tymczasowego, a następnie załadowanie go w razie potrzeby. Kiedy go załadujesz musisz jednak tymczasowo potwierdzić uprawnienia w AppDomain, ponieważ zablokowałeś dostęp do systemu plików. Oto przykładowy fragment tego:

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

Stamtąd możesz użyć assembly i reflection, aby wywołać swoją metodę. Zauważ, że ta metoda pozwala przenieść proces kompilacji poza sandboxed AppDomain, co jest moim zdaniem plusem.

Dla odniesienia, oto moja klasa piaskownicy stworzona, aby ułatwić uruchamianie zestawów skryptów w ładnym Wyczyść oddzielną Appdomenę, która ma ograniczone uprawnienia i może być łatwo rozładowana, gdy jest to konieczne:

class Sandbox : MarshalByRefObject
{
    const string BaseDirectory = "Untrusted";
    const string 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.RestrictedMemberAccess));
        permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));

        var domain = AppDomain.CreateDomain(DomainName, null, setup, permissions,
            typeof(Sandbox).Assembly.Evidence.GetHostEvidence<StrongName>());

        return (Sandbox)Activator.CreateInstanceFrom(domain, typeof(Sandbox).Assembly.ManifestModule.FullyQualifiedName, typeof(Sandbox).FullName).Unwrap();
    }

    public string Execute(string assemblyPath, string scriptType, string 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 string.Format("{0}", type.GetMethod(method).Invoke(instance, parameters));
    }
}

Szybka uwaga: jeśli używasz tej metody do dostarczania dowodów bezpieczeństwa dla nowego AppDomain, musisz podpisać swój zespół, aby nadać mu mocną nazwę.

Zauważ, że działa to dobrze podczas uruchamiania w procesie, ale jeśli naprawdę chcesz mieć doskonałe środowisko skryptów, musisz pójść o krok dalej i wyizolować skrypt w osobnym procesie, aby upewnić się, że skrypty, które robią złośliwe (lub złośliwe) po prostu głupie) rzeczy takie jak przepełnienia stosu, fork bomb i sytuacje z pamięci nie obniżają całego procesu aplikacji. Mogę dać ci więcej informacji na ten temat, jeśli potrzebujesz.

 42
Author: MikeP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-14 09:49:25