2012年3月14日 星期三

組件的安全性

CAS 是一種用來限制資源被存取的機制,包括檔案、目錄、印表機、網路存取...。 .NET Framework 對每個可以被保護資源各提供一類別,定義在 System.Security.Permissions 命名空間裡。 每個類別都有各自的特定成員,藉以控制相關資源的使用權限。例如:

雖然各個權限類別有其特殊的屬性設定值,不過這些類別都繼承自 CodeAccessSecurity 類別,所以只須熟悉二種標準的屬性即可:

  • Action:指定執行哪個安全性動作,可使用 SecurityAction 列舉值來設定此屬性。
  • Unrestricted:若要表示 full permission,則值設成 true ,此時會完全忽略 CAS 的設定。反之則 false 。

Action 屬性,共有下列三種列舉成員:

  1. RequestMinimum (M) :授與指定的使用權限。
  2. RequestOptional (O) :僅授與指定的使用權限。這個要求隱含地拒絕所有其他未授與的使用權限。
  3. RequestRefuse (R) :拒絕使用權限。

這三種設定值若重複指定,其結果判斷規則如下:
若某一組件,其原先的 Security Policy (也就是Enterprise, Machine, User三者的交集) 為 P, 經過 SecurityAction 設定後,最終的權限為:
(P 交((M 聯 O) - R))

如何建立組件宣告

底下程式碼示範,組件必須具備 C:\boot.ini 的讀取權限,才可以執行。

[assembly:FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read=@"C:\boot.ini")]
namespace DeclarativeExample
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

範例1

以下範列假設使用管理員帳號與 Everything 的使用權限,說明各種狀況下的權限變化。

[assembly: FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read = @"C:\Log.txt")]
對象ReadWriteAppend
C:\Log.txtyesyesyes
C:\Log2.txtyesyesyes

範例2

[assembly: FileIOPermissionAttribute(SecurityAction.RequestOptional, Read = @"C:\Log.txt")]
對象ReadWriteAppend
C:\Log.txtyesnono
C:\Log2.txtnonono

範例3

[assembly: FileIOPermissionAttribute(SecurityAction.RequestOptional, Read = @"C:\Log.txt", Write = @"C:\Log.txt")]
[assembly: FileIOPermissionAttribute(SecurityAction.RequestOptional, Append = @"C:\Log.txt")]
對象ReadWriteAppend
C:\Log.txtyesyesyes
C:\Log2.txtnonono

範例4

[assembly: FileIOPermissionAttribute(SecurityAction.RequestOptional, Read = @"C:\temp")]
對象ReadWriteAppend
C:\temp\Log.txtyesnono
C:\temp\Log2.txtyesnono
C:\temp2\Log.txtnonono
C:\Log.txtnonono

範例5

[assembly: FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read = @"C:\temp")]
[assembly: FileIOPermissionAttribute(SecurityAction.RequestOptional, Append = @"C:\temp2")]
對象ReadWriteAppend
C:\temp\Log.txtyesnono
C:\temp2\log.txtnonoyes
C:\Log.txtnonono

範例6

[assembly: FileIOPermissionAttribute(SecurityAction.RequestMinimum, Read = @"C:\temp")]
[assembly: FileIOPermissionAttribute(SecurityAction.RequestRefuse, Read = @"C:\temp")]
對象ReadWriteAppend
C:\temp\Log.txtnoyesyes

範例7

[assembly: FileIOPermissionAttribute(SecurityAction.RequestOptional, Write = @"C:\temp")]
[assembly: FileIOPermissionAttribute(SecurityAction.RequestRefuse, Read = @"C:\temp")]
對象ReadWriteAppend
C:\temp\Log.txtnoyesno

如何在沙箱作業中,限定組件的權限

例一:

下面這個例子,我們要在主應用程式中,使用沙箱作業,載入 C:\plugins\SandTest.exe 這個組件。
我們使用 PermissionSet ,限定 SandTest 這個組件只能讀取 C:\temp\test1 目錄中的檔案,其他目錄則不允許存取。

string pluginFolder = @"C:\plugins";
string plugInPath = @"C:\plugins\SandTest.exe");

PermissionSet pSet = new PermissionSet(PermissionState.None);
pSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
pSet.AddPermission(new UIPermission(PermissionState.Unrestricted));
pSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, pluginFolder));
pSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, @"C:\temp\test1"));

AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation;
AppDomain sandbox = AppDomain.CreateDomain("sbox", null, setup, pSet);
sandbox.ExecuteAssembly(plugInPath);
AppDomain.Unload(sandbox);

例二:

下面這個例子,我們透過 Evidence 來限定組件的執行權限。

首先我們建立一個權限集合,如下圖所示:

再建立一個程式碼群組,如下圖所示:

程式碼部分如下,

private void button27_Click(object sender, EventArgs e)
{
    string pluginFolder = @"D:\myBlog\TestProj\TestForAppDomain\TestForAppDomain\bin\Debug";
    string plugInPath = Path.Combine(pluginFolder, "TestForAppDomain.exe");

    Assembly asm = Assembly.LoadFile(plugInPath);
            
    AppDomainSetup setup = new AppDomainSetup();
    setup.ApplicationBase = pluginFolder;

    //設定 sandbox 執行的權限
    Evidence hostEvidence = new Evidence();
    hostEvidence.AddHost(new Site("www.vito.com"));

    PermissionSet pset = SecurityManager.ResolvePolicy(hostEvidence);
    pset.AddPermission(new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, pluginFolder));
    pset.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
    pset.AddPermission(new UIPermission(PermissionState.Unrestricted));

    //建立 sandbox
    AppDomain sandbox = AppDomain.CreateDomain("sbox", hostEvidence, setup, pset);  //指定 host 的 Evidence 和 權限集合

    //建立 assebmlyEvidence
    Evidence asmEvidence = new Evidence();
    asmEvidence.AddAssembly(new Site("www.vito.com"));      //指定組件的 Evidence

    //在 sandbox 執行組件
    sandbox.ExecuteAssembly(plugInPath);

    AppDomain.Unload(sandbox);
}

沒有留言:

張貼留言