2

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

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

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

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

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

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

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

1 回答 1

3
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 : resolution 如何通过查看 SLAVE (CurrentDomain) 找到 SLAVE 中的程序集,听起来像一个恶性循环

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

:为什么它会中断 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# 规范:

对于具有隐式入口点的可执行文件,出现在命令行上的最后一个文件的静态初始化程序是隐式入口点函数的主体。

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

于 2012-11-08T06:50:28.127 回答