【问题标题】:Should ApplicationBase be different for the sandbox AppDomain?沙盒 AppDomain 的 ApplicationBase 是否应该不同?
【发布时间】:2012-11-07 23:45:41
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

    标签: .net f# clr sandbox appdomain


    【解决方案1】:
    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:解析如何通过查看SLAVE(CurrentDomain)找到SLAVE中的程序集,听起来是个恶性循环

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

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

    Assembly.GetName 需要 FileIOPermission、Assembly.FullName - 如果您替换,请不要这样

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

    这应该也可以(没试过)

    :为什么它会因为静态而刹车呢?AssemblyResolveSetup.install()

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

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

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

    【讨论】:

    • 很高兴让它工作,想评论它为什么工作? (1) 分辨率如何通过查看 SLAVE (CurrentDomain) 在 SLAVE 中找到程序集,这听起来像是一个恶性循环 (2) 为什么它会因asm.GetName() 而不是AssemblyName(asm.FullName) 而中断 (3) 为什么它会因static do AssemblyResolveSetup.install() 而刹车?
    猜你喜欢
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 2011-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多