沙盒 AppDomain 的 ApplicationBase 应该不同吗? [英] Should ApplicationBase be different for the sandbox AppDomain?

查看:30
本文介绍了沙盒 AppDomain 的 ApplicationBase 应该不同吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将从属沙盒域的 ApplicationBase 设置为与托管域相同的路径有什么确切的安全含义?

What are the exact security implications of setting ApplicationBase of a slave sandbox domain to the same path as the hosting domain?

我发现 MSDN 指南指出 ApplicationBase 对于从属域应该不同如果 ApplicationBase 设置相同,则部分信任应用程序可以让托管应用程序加载(作为完全信任)它定义的异常,因此利用它"(第 3 页):

I found MSDN guidelines that state that ApplicationBase should be different for the slave domain "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" (p. 3):

http://msdn.microsoft.com/en-us/library/bb763046.aspx

这个漏洞究竟是如何工作的?

How exactly would this exploit work?

在我的场景中,我愿意完全信任地运行位于 ApplicationBase 下的所有程序集.我专门对从属 AppDomain 进行沙盒处理,以限制该域内动态生成的程序集的权限.我尝试遵循指南,但更改 ApplicationBase 属性似乎破坏了域之间的双向通信桥,因为程序集加载到 LoadFrom 上下文中,所以我想避免它.

In my scenario I am willing to run all assemblies located under the ApplicationBase in full trust. I am sandboxing the slave AppDomain exclusively to limit the rights of dynamically generated assemblies within that domain. I tried following the guidelines but changing the ApplicationBase property seems to break a bi-directional communication bridge I have between the domains, due to an assembly loading into LoadFrom context, so I would like to avoid it.

示例 F# 代码演示了具有不同 ApplicationBase 值的问题:

Sample F# code demonstrating the problem with distinct ApplicationBase values:

module Main =

    open System
    open System.Diagnostics
    open System.IO
    open System.Reflection
    open System.Security
    open System.Security.Permissions
    open System.Security.Policy

    /// Change this switch to observe the problem.
    let useSameApplicationBase = true

    let getStrongName (a: Assembly) =
        match a.Evidence.GetHostEvidence<StrongName>() with
        | null -> None
        | sn -> Some sn

    let getAssemblies () =
        [|
            Assembly.GetExecutingAssembly()
        |]

    let buildAppDomain () =
        let fullTrust =
            getAssemblies ()
            |> Array.choose getStrongName
        let evidence = null
        let appBase =
            if useSameApplicationBase then
                AppDomain.CurrentDomain.BaseDirectory
            else
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Untrusted")
        let setup = AppDomainSetup(ApplicationBase = appBase)
        let perms = PermissionSet(PermissionState.None)
        AppDomain.CreateDomain("SLAVE", null, setup, perms, fullTrust)

    [<Sealed>]
    type Backer() =
        inherit MarshalByRefObject()
        member this.Pong() =
            Console.WriteLine("PONG IN DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)

    [<Sealed>]
    type Sandbox() =
        inherit MarshalByRefObject()
        member this.Start(backer: obj) =
            Console.WriteLine("RUN IN SLAVE DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)
            (backer :?> Backer).Pong()

    let test () =
        let dom = buildAppDomain ()
        try
            let handle =
                Activator.CreateInstanceFrom(dom,
                    typeof<Sandbox>.Assembly.Location,
                    typeof<Sandbox>.FullName)
            let sandbox = handle.Unwrap() :?> Sandbox
            sandbox.Start(Backer())
        finally
            AppDomain.Unload(dom)

    test ()

推荐答案

module Main =

    open System
    open System.Diagnostics
    open System.IO
    open System.Reflection
    open System.Security
    open System.Security.Permissions
    open System.Security.Policy

    /// Change this switch to observe the problem.
    let useSameApplicationBase = false

    let getStrongName (a: Assembly) =
        match a.Evidence.GetHostEvidence<StrongName>() with
        | null -> None
        | sn -> Some sn

    let getAssemblies () =
        [|
            Assembly.GetExecutingAssembly()
        |]

    let buildAppDomain () =
        let fullTrust =
            getAssemblies ()
            |> Array.choose getStrongName
        let evidence = null
        let appBase =
            if useSameApplicationBase then
                AppDomain.CurrentDomain.BaseDirectory
            else
                Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Untrusted")
        let setup = AppDomainSetup(ApplicationBase = appBase)
        let perms = PermissionSet(PermissionState.None)
        AppDomain.CreateDomain("SLAVE", null, setup, perms, fullTrust)

    module AssemblyResolveSetup = 
        let install() = 
            let resolveHandler = 
                    ResolveEventHandler(
                        fun _ args ->
                            // try to find requested assembly in current domain
                            let name = AssemblyName(args.Name)
                            let asmOpt =
                                AppDomain.CurrentDomain.GetAssemblies()
                                |> Array.tryFind(fun asm -> AssemblyName.ReferenceMatchesDefinition(AssemblyName(asm.FullName), name))
                            defaultArg asmOpt null
                    )        
            AppDomain.CurrentDomain.add_AssemblyResolve(resolveHandler)

    [<Sealed>]
    type Backer() =
        inherit MarshalByRefObject()
        member this.Pong() =
            Console.WriteLine("PONG IN DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)

    [<Sealed>]
    type Sandbox() =
        inherit MarshalByRefObject()
        do AssemblyResolveSetup.install()
        member this.Start(backer: obj) =
            Console.WriteLine("RUN IN SLAVE DOMAIN = {0}", AppDomain.CurrentDomain.FriendlyName)
            (backer :?> Backer).Pong()

    let test () =
        let dom = buildAppDomain ()
        try
            let handle =
                Activator.CreateInstanceFrom(dom,
                    typeof<Sandbox>.Assembly.Location,
                    typeof<Sandbox>.FullName)
            let sandbox = handle.Unwrap() :?> Sandbox
            sandbox.Start(Backer())
        finally
            AppDomain.Unload(dom)

    test ()

更新(假设测试代码包含在程序集 Sandbox.exe 中)

Q:resolve如何通过查看SLAVE(CurrentDomain)找到SLAVE中的程序集,听起来像一个恶性循环

Q:how resolution finds the assembly in SLAVE by looking in SLAVE (CurrentDomain), sounds like a vicious circle

SLAVE 域已经包含 Sandbox.exe,但它是在 LoadFrom 上下文中加载的,因此在解析 Load 上下文的依赖项时不会自动探测它 (选择绑定上下文).

SLAVE domain already contains Sandbox.exe but it is loaded in LoadFrom context so it won't be probed automatically when resolving dependencies for Load context (Choosing a binding context).

Q:为什么它会因 asm.GetName() 而不是 AssemblyName(asm.FullName) 中断

Q: why it breaks for asm.GetName() instead of AssemblyName(asm.FullName)

Assembly.GetName 需要 FileIOPermission、Assembly.FullName - 如果你替换的话,我认为不要这样

Assembly.GetName requires FileIOPermission, Assembly.FullName - don't so I think if you replace

AssemblyName(asm.FullName)

let name = AssemblyName(args.Name)
let p = new FileIOPermission(PermissionState.Unrestricted)
p.Assert()
try
    let asmOpt =
        AppDomain.CurrentDomain.GetAssemblies()
        |> Array.tryFind(fun asm -> AssemblyName.ReferenceMatchesDefinition(asm.GetName(), name))
    defaultArg asmOpt null
finally
    CodeAccessPermission.RevertAssert()

这也应该有效(没试过)

this should also work (haven't tried)

Q:为什么它会为静态 do AssemblyResolveSetup.install() 刹车

Q: why it brakes for static do AssemblyResolveSetup.install()

这是这里唯一的 F# 特定问题.我猜您的测试项目是编译为 exe 的单文件项目.根据 F# 规范:

this is the only F# specific issue here. I guess your test project is single file project that is compiled to exe. Per F# spec:

对于具有隐式入口点的可执行文件,出现在命令行是隐式入口点函数的主体.

因此,'static do' 块中的代码将放置在隐式入口点中对 'test()' 的调用之前,而不是被编译到静态构造函数的主体中.修复 - 要么将测试模块放在单独的非最后一个文件中,要么将其移动到库中

So code in 'static do' block will be placed before the call to 'test()' in the implicit entry point instead of being compiled to the body of static constructor. Fix - either put Test module to the separate non-last file or move it to the library

这篇关于沙盒 AppDomain 的 ApplicationBase 应该不同吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆