首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

為 WCF 引入代碼存取安全性(CAS)第 2 部:部分信任服務與 AppDomainHost 實作全解析

     編輯:關於.NET

.NET 3.5 宿主端 CAS 現況與限制

.NET 3.5 僅允許 BasicHttpBinding、WSHttpBinding、WebHttpBinding 在部分信任下宿主服務,且限無安全性或僅 Transport 安全;WSHttpBinding 禁用訊息安全、可靠傳訊、交易。所有部分信任綁定強制文字編碼,無法使用診斷/效能計數器。綁定隱式要求宿主權限(圖 1):執行權限、基礎結構安全權限、Web 權限(接受 URI)、非受控反射(跨組件 internal 類型)、主體控制權限(驗證後)。

缺點:權限隱式授予服務實例,服務可控制主體、反射宿主其他組件。理想模式:宿主根據風險授予最小權限集,服務權限為宿主子集。

部分信任服務:權限屬性與 PermitOnly

在服務類別標記 [SecurityPermission(SecurityAction.PermitOnly, Execution=true)] 等屬性,運行時合併為單一權限集,堆疊修飾符主動拒絕所有未列權限。嘗試存取檔案即拋出 SecurityException。視窗標題會顯示「部分信任」警告。

部分信任視窗警告

進階用法:將權限定義於 XML 檔(MyServicePermissions.xml),編譯時嵌入中繼資料,部署後可修改檔案調整權限(需重新編譯)。

<PermissionSet class="System.Security.PermissionSet">
  <IPermission class="System.Security.Permissions.SecurityPermission" Flags="Execution" />
  <IPermission class="System.Security.Permissions.UIPermission" Window="SafeTopLevelWindows" />
</PermissionSet>
[PermissionSet(SecurityAction.PermitOnly, File="MyServicePermissions.xml")]
class MyService : IMyContract { ... }

AppDomainHost:隔離與授權的關鍵基礎設施

基於屬性的做法三大缺點:

  1. 服務變更需修改屬性/檔案,耦合度高。
  2. 無法在同一宿主對同一服務類型授予不同權限。
  3. 現實中服務極少主動分析所需最小權限;宿主應決定授予何種權限。

AppDomainHost 將服務載入獨立 AppDomain,並可指定權限集。用法如 ServiceHost:

// 完全信任
AppDomainHost host0 = new AppDomainHost(typeof(MyService), "Full Trust", new Uri("net.tcp://localhost:6000"));
host0.Open();

// 部分信任:僅執行與安全視窗權限
PermissionSet permissions = new PermissionSet(PermissionState.None);
permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
permissions.AddPermission(new UIPermission(UIPermissionWindow.SafeTopLevelWindows));
AppDomainHost host1 = new AppDomainHost(typeof(MyService), permissions, "Partial Trust", new Uri("net.tcp://localhost:6001"));
host1.Open();

// 權限不足
PermissionSet permissions2 = new PermissionSet(PermissionState.None);
permissions2.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
AppDomainHost host2 = new AppDomainHost(typeof(MyService), permissions2, "Not Enough", new Uri("net.tcp://localhost:6002"));
host2.Open();

// 命名權限集
AppDomainHost host3 = new AppDomainHost(typeof(MyService), StandardPermissionSet.Internet, "Internet Zone", new Uri("net.tcp://localhost:6003"));
host3.Open();

不同權限同服務類型並存

AppDomainHost 實作核心:ServiceHostActivator 與 CAS 策略注入

  1. ServiceHostActivator 繼承 MarshalByRefObject,跨 AppDomain 封裝 ServiceHost 建立/開啟/關閉。
  2. AppDomainHost 建構子鏈最終呼叫受保護建構子:
    - AppDomain.CreateDomain 建立新域(預設 FullTrust)。
    - CreateInstanceAndUnwrap 注入 Activator 代理。
    - CodeAccessSecurityHelper.SetPermissionsSet 在新域安裝 CAS 策略:
    PolicyLevel policy = PolicyLevel.CreateAppDomainLevel();
    policy.RootCodeGroup.PolicyStatement = new PolicyStatement(permissions);
    appDomain.SetAppDomainPolicy(policy);
    
    - 呼叫 Activator.CreateHost 建立 ServiceHost(此時在新域執行,受新策略限制)。
  3. Open/Close/Abort 透過代理轉發至 Activator。

ClickOnce 使用相同技術強制部分信任。

部分信任宿主:結構化宿主端安全要求

若宿主程式碼本身為部分信任,不能讓 AppDomainHost/Activator 空白 Assert FullTrust(會繞過 CAS、造成權限提升攻擊)。解決方案:

  1. Activator.CreateHost 以程式碼 Assert FullTrust 建立 ServiceHost,隨即 RevertAssert。
  2. 呼叫 DemandHostPermissions 針對端點配置主動要求宿主權限(圖 10):
    - TCP:執行 + Socket 接受權限
    - IPC:執行 + 控制策略/證據
    - MSMQ:執行 + 讀取佇列
    - HTTP 系:執行 + Web 接受權限
    - 可靠傳訊/雙工/非同步:控制策略/證據
    - 交易流:不受限分散式交易權限
    - 憑證存取:列舉/開啟/列舉存儲區
    - 診斷追蹤:環境變數 COMPUTERNAME + 檔案 I/O
    - 效能計數器:寫入計數器權限
    - ASP.NET Provider:最小 ASP.NET 宿主權限

結構化要求實作節錄

public static void DemandHostPermissions(this ServiceHost host)
{
    foreach (ServiceEndpoint ep in host.Description.Endpoints)
    {
        DemandHostConnectionPermissions(ep);
        DemandHostSecurityPermissions(ep);
        using (TransactionScope scope = new TransactionScope())
            DemandTransactionPermissions(ep);
    }
    DemandHostStorePermissions(host);
    DemandPerformanceCounterPermissions();
    DemandTracingPermissions();
    DemandAspNetProvidersPermissions(host);
}

static void DemandHostConnectionPermissions(ServiceEndpoint ep)
{
    PermissionSet set = new PermissionSet(PermissionState.None);
    if (ep.Binding is NetTcpBinding)
    {
        set.AddPermission(new SocketPermission(NetworkAccess.Accept, TransportType.Tcp,
            ep.Address.Uri.Host, ep.Address.Uri.Port));
    }
    // ... 其他綁定檢查
    set.Demand();
}

AppDomainHost 建構子在建立新域前先 permissions.Demand(),確保呼叫者擁有至少服務所需權限,防止部分信任代碼透過宿主提權。

AppDomainHost 進階特性

  • 事件模型與狀態機管理(非 ICommunicationObject)。
  • 複製靜態變數至新域:ASP.NET Provider 應用程式名稱(臨時 Assert AspNetHostingPermission 讀取後 RevertAssert)。
  • 支援多實例並行,各自獨立權限與端點。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved