WPF 部分信任安全性

一般而言,網際網路應用程式應該限制不得直接存取重要的系統資源,以防止惡意損害。 根據預設,HTML 和用戶端腳本語言無法存取重要的系統資源。 由於可以從瀏覽器啟動 Windows Presentation Foundation (WPF) 瀏覽器裝載的應用程式,因此應該符合一組類似的限制。 若要強制執行這些限制,WPF 依賴程式代碼存取安全性 (CAS) 和 ClickOnce (請參閱 WPF 安全性策略 - 平台安全性)。 根據預設,瀏覽器裝載的應用程式會要求因特網區域 CAS 許可權集,無論它們是從因特網、本機內部網路或本機計算機啟動。 使用少於完整權限集執行的應用程式便是以部分信任執行。

WPF 提供各種不同的支援,以確保盡可能多的功能可以安全地用於部分信任,以及 CAS,為部分信任程序設計提供額外的支援。

本主題包含下列幾節:

WPF 功能部分信任支援

下表列出 Windows Presentation Foundation (WPF) 的高階功能,這些功能可安全地在因特網區域許可權集合的限制內使用。

表 1:在部分信任中安全的 WPF 功能

功能區域 功能
一般 瀏覽器視窗

原始站台存取

IsolatedStorage (512 KB 限制)

UIAutomation 提供者

命令

輸入法 (IME)

平板電腦手寫筆和筆跡

使用滑鼠捕捉和移動事件模擬拖放

OpenFileDialog

XAML 還原序列化 (透過 XamlReader.Load)
Web 整合 瀏覽器下載對話方塊

最上層使用者啟始的瀏覽

mailto:links

統一資源識別項參數

HTTPWebRequest

在 IFRAME 中裝載的 WPF 內容

使用框架裝載相同站台的 HTML 頁面

使用網頁瀏覽器裝載相同站台的 HTML 頁面

Web 服務 (ASMX)

Web 服務 (使用 Windows Communication Foundation)

指令碼

文件物件模型
視覺效果 2D 和 3D

動畫

媒體 (原始站台和跨網域)

影像處理/音訊/視訊
讀取 FlowDocuments

XPS 文件

內嵌與系統字型

CFF 與 TrueType 字型
編輯 拼字檢查

RichTextBox

純文字和筆跡剪貼簿支援

使用者啟始的貼上

複製選取的內容
控制項 一般控制項

下表涵蓋高階的 WPF 功能。 如需詳細資訊,Windows SDK 會記錄 WPF 中每個成員所需的許可權。 此外,下列功能有關於部分信任執行的更詳細資訊,包括特殊考量。

下表概述在因特網區域許可權集合限制內執行不安全的 WPF 功能。

表 2:在部分信任中不安全的 WPF 功能

功能區域 功能
一般 視窗 (應用程式定義的視窗和對話方塊)

SaveFileDialog

File System

登錄存取

拖放功能

XAML 序列化 (透過 XamlWriter.Save)

UIAutomation 用戶端

來源視窗存取 (HwndHost)

完整的語音支援

Windows Forms 互通性
視覺效果 點陣圖效果

影像編碼
編輯 RTF 格式剪貼簿

完整的 XAML 支援

部分信任程式設計

針對 XBAP 應用程式,超過預設許可權集的程式代碼會根據安全性區域而有不同的行為。 在某些情況下,使用者會在嘗試安裝它時收到一則警告。 使用者可以選擇繼續或取消安裝。 下表描述每個安全性區域的應用程式行為,以及您必須針對應用程式執行什麼動作才能得到完全信任。

警告

XBAP 需要舊版瀏覽器才能運作,例如 Internet Explorer 和 Firefox。 Windows 10 和 Windows 11 通常不支援這些舊版瀏覽器版本。 由於安全性風險,新式瀏覽器不再支援 XBAP 應用程式所需的技術。 不再支援啟用 XBAP 的外掛程式。

安全性區域 行為 取得完全信任
本機電腦 自動的完全信任 不需要採取任何動作。
內部網路和信任的網站 完全信任的提示 使用憑證簽署 XBAP,讓使用者在提示中看到來源。
網際網路 因為「未授與信任」而失敗 使用憑證簽署 XBAP。

注意

上表中描述的行為是針對未遵循 ClickOnce 受信任部署模型的完全信任 XBAP。

一般而言,可能超過允許權限的程式碼很可能是在獨立式與瀏覽器裝載的應用程式之間共用的通用程式碼。 CAS 和 WPF 提供數種管理此案例的技術。

使用 CAS 偵測權限

在某些情況下,獨立應用程式和 XBAP 都可以在連結庫元件中使用共用程式代碼。 在這些情況下,程式碼執行的功能,所需的權限可能會超過應用程式的已授與權限集合所允許的權限。 您的應用程式可以使用 Microsoft .NET Framework 安全性來偵測它是否有特定許可權。 具體來說,它可以藉由在所需許可權的實例上呼叫 Demand 方法,測試它是否具有特定許可權。 這會顯示在下列的範例中,程式碼會查詢它是否能夠將檔案儲存到本機磁碟︰

using System.IO;
using System.IO.IsolatedStorage;
using System.Security;
using System.Security.Permissions;
using System.Windows;

namespace SDKSample
{
    public class FileHandling
    {
        public void Save()
        {
            if (IsPermissionGranted(new FileIOPermission(FileIOPermissionAccess.Write, @"c:\newfile.txt")))
            {
                // Write to local disk
                using (FileStream stream = File.Create(@"c:\newfile.txt"))
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.WriteLine("I can write to local disk.");
                }
            }
            else
            {
                MessageBox.Show("I can't write to local disk.");
            }
        }

        // Detect whether or not this application has the requested permission
        bool IsPermissionGranted(CodeAccessPermission requestedPermission)
        {
            try
            {
                // Try and get this permission
                requestedPermission.Demand();
                return true;
            }
            catch
            {
                return false;
            }
        }


Imports System.IO
Imports System.IO.IsolatedStorage
Imports System.Security
Imports System.Security.Permissions
Imports System.Windows

Namespace SDKSample
    Public Class FileHandling
        Public Sub Save()
            If IsPermissionGranted(New FileIOPermission(FileIOPermissionAccess.Write, "c:\newfile.txt")) Then
                ' Write to local disk
                Using stream As FileStream = File.Create("c:\newfile.txt")
                Using writer As New StreamWriter(stream)
                    writer.WriteLine("I can write to local disk.")
                End Using
                End Using
            Else
                MessageBox.Show("I can't write to local disk.")
            End If
        End Sub

        ' Detect whether or not this application has the requested permission
        Private Function IsPermissionGranted(ByVal requestedPermission As CodeAccessPermission) As Boolean
            Try
                ' Try and get this permission
                requestedPermission.Demand()
                Return True
            Catch
                Return False
            End Try
        End Function

    }
}
    End Class
End Namespace

如果應用程式沒有所需的許可權,對的呼叫 Demand 將會擲回安全性例外狀況。 否則,便已授與權限。 IsPermissionGranted 封裝此行為,並視需要傳 true 回 或 false

功能正常降級

能夠偵測程式碼是否有權執行它需要做的事,對於可以從不同區域執行的程式碼而言很有趣。 不過偵測區域是一件事,可能的話,為使用者提供替代方式會好上許多。 比方說,完全信任應用程式通常可讓使用者在任何想要的地方建立檔案,而部分信任應用程式則只能在隔離儲存區建立檔案。 如果建立檔案的程式碼存在於完全信任 (獨立式) 應用程式和部分信任 (瀏覽器裝載) 應用程式所共用的組件中,而且兩個應用程式都想要讓使用者能夠建立檔案,則共用的程式碼應該先偵測它是在部分信任還是完全信任中執行,然後才能在適當位置中建立檔案。 下列程式碼可示範兩種情況。

using System.IO;
using System.IO.IsolatedStorage;
using System.Security;
using System.Security.Permissions;
using System.Windows;

namespace SDKSample
{
    public class FileHandlingGraceful
    {
        public void Save()
        {
            if (IsPermissionGranted(new FileIOPermission(FileIOPermissionAccess.Write, @"c:\newfile.txt")))
            {
                // Write to local disk
                using (FileStream stream = File.Create(@"c:\newfile.txt"))
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.WriteLine("I can write to local disk.");
                }
            }
            else
            {
                // Persist application-scope property to
                // isolated storage
                IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
                using (IsolatedStorageFileStream stream =
                    new IsolatedStorageFileStream("newfile.txt", FileMode.Create, storage))
                using (StreamWriter writer = new StreamWriter(stream))
                {
                    writer.WriteLine("I can write to Isolated Storage");
                }
            }
        }

        // Detect whether or not this application has the requested permission
        bool IsPermissionGranted(CodeAccessPermission requestedPermission)
        {
            try
            {
                // Try and get this permission
                requestedPermission.Demand();
                return true;
            }
            catch
            {
                return false;
            }
        }


Imports System.IO
Imports System.IO.IsolatedStorage
Imports System.Security
Imports System.Security.Permissions
Imports System.Windows

Namespace SDKSample
    Public Class FileHandlingGraceful
        Public Sub Save()
            If IsPermissionGranted(New FileIOPermission(FileIOPermissionAccess.Write, "c:\newfile.txt")) Then
                ' Write to local disk
                Using stream As FileStream = File.Create("c:\newfile.txt")
                Using writer As New StreamWriter(stream)
                    writer.WriteLine("I can write to local disk.")
                End Using
                End Using
            Else
                ' Persist application-scope property to 
                ' isolated storage
                Dim storage As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
                Using stream As New IsolatedStorageFileStream("newfile.txt", FileMode.Create, storage)
                Using writer As New StreamWriter(stream)
                    writer.WriteLine("I can write to Isolated Storage")
                End Using
                End Using
            End If
        End Sub

        ' Detect whether or not this application has the requested permission
        Private Function IsPermissionGranted(ByVal requestedPermission As CodeAccessPermission) As Boolean
            Try
                ' Try and get this permission
                requestedPermission.Demand()
                Return True
            Catch
                Return False
            End Try
        End Function

    }
}
    End Class
End Namespace

在許多情況下,您應該能夠找到部分信任的替代方法。

在受控環境中,例如內部網路,自定義受控架構可以安裝在用戶端基底到全域程式集緩存 (GAC)。 這些連結庫可以執行需要完全信任的程式代碼,而且只能使用 AllowPartiallyTrustedCallersAttribute 從只允許部分信任的應用程式參考 (如需詳細資訊,請參閱 安全性和WPF 安全性策略 - 平臺安全性)。

瀏覽器裝載偵測

當您需要根據每個許可權檢查時,使用 CAS 來檢查許可權是適當的技術。 不過,這項技巧依賴在一般處理時攔截例外狀況,一般而言不建議這麼做,其可能會發生效能問題。 相反地,如果您的 XAML 瀏覽器應用程式 (XBAP) 只會在因特網區域沙箱內執行,您可以使用 BrowserInteropHelper.IsBrowserHosted 屬性,這會針對 XAML 瀏覽器應用程式 (XBAP) 傳回 true。

警告

XBAP 需要舊版瀏覽器才能運作,例如 Internet Explorer 和 Firefox。 Windows 10 和 Windows 11 通常不支援這些舊版瀏覽器版本。 由於安全性風險,新式瀏覽器不再支援 XBAP 應用程式所需的技術。 不再支援啟用 XBAP 的外掛程式。

注意

IsBrowserHosted 只會區分應用程式是否在瀏覽器中執行,而不是應用程式正在執行的許可權集。

管理權限

根據預設,XBAP 會以部分信任執行(預設因特網區域許可權集合)。 不過,根據應用程式的需求,也可以變更預設的權限集合。 例如,如果 XBAP 是從本機內部網路啟動,它可以利用增加的許可權集,如下表所示。

警告

XBAP 需要舊版瀏覽器才能運作,例如 Internet Explorer 和 Firefox。 Windows 10 和 Windows 11 通常不支援這些舊版瀏覽器版本。 由於安全性風險,新式瀏覽器不再支援 XBAP 應用程式所需的技術。 不再支援啟用 XBAP 的外掛程式。

表 3︰近端內部網路和網際網路權限

權限 屬性 LocalIntranet 網際網路
DNS 存取 DNS 伺服器 No
環境變數 參閱 No
檔案對話方塊 開啟 Yes Yes
檔案對話方塊 不受限制 No
隔離儲存區 依據使用者隔離組件 No
隔離儲存區 未知的隔離 Yes Yes
隔離儲存區 無限制的使用者配額 No
媒體 安全的音訊、視訊和影像 Yes Yes
列印 預設列印 No
列印 安全列印 Yes Yes
反映 發出 No
安全性 Managed 程式碼執行 Yes Yes
安全性 判斷提示授與權限 No
使用者介面 不受限制 No
使用者介面 安全的最上層視窗 Yes Yes
使用者介面 擁有剪貼簿 Yes Yes
Web Browser HTML 框架安全瀏覽 Yes

注意

在部分信任中,只有在使用者啟動時,才允許剪下和貼上。

如果您需要提高權限,您需要變更專案設定和 ClickOnce 應用程式資訊清單。 如需詳細資訊,請參閱 WPF XAML 瀏覽器應用程式概觀。 下列文件可能有用。

如果您的 XBAP 需要完全信任,您可以使用相同的工具來增加要求的許可權。 雖然 XBAP 只有在安裝在本機計算機、內部網路或從瀏覽器信任或允許的網站所列的 URL 上啟動時,才會收到完全信任。 如果應用程式是從內部網路或受信任的網站安裝,使用者會收到標準 ClickOnce 提示,通知他們權限已提高。 使用者可以選擇繼續或取消安裝。

或者,您可以使用 ClickOnce 受信任部署模型,以從任何安全性區域進行完全信任部署。 如需詳細資訊,請參閱受信任應用程式部署概觀安全性

另請參閱