WPF 部分信任安全性

通常,应限制 Internet 应用程序直接访问关键系统资源,以防止恶意损坏。 默认情况下,HTML 和客户端脚本语言无法访问关键系统资源。 由于可以从浏览器启动 Windows Presentation Foundation(WPF)浏览器托管的应用程序,因此它们应符合类似的一组限制。 为了强制实施这些限制,WPF 依赖于代码访问安全性(CAS)和 ClickOnce(请参阅 WPF 安全策略 - 平台安全性)。 默认情况下,浏览器托管的应用程序会请求 Internet 区域 CAS 权限集,而不管它们是从 Internet、本地 Intranet 还是本地计算机启动的。 据说,使用不低于完整权限集运行的应用程序会以部分信任方式运行。

警告

XBAP 要求旧版浏览器运行,例如 Internet Explorer 和旧版 Firefox。 这些较旧的浏览器通常在 Windows 10 和 Windows 11 上不受支持。 由于安全风险,新式浏览器不再支持 XBAP 应用所需的技术。 不再支持启用 XBAP 的插件。 有关详细信息,请参阅 有关 WPF 浏览器托管应用程序(XBAP)的常见问题解答。

WPF 提供了多种支持,确保最大限度功能在部分信任环境中安全使用,并且与 CAS 一起,为部分信任编程提供额外支持。

本主题包含以下部分:

WPF 功能部分信任支持

警告

新式 .NET 不支持代码访问安全性(CAS),它是仅限 .NET Framework 的概念。 所有与 CAS 相关的功能都根据完全信任的假设进行处理。 有关详细信息,请参阅 WPF .NET 的差异 - 代码访问安全性

下表列出了 Windows Presentation Foundation(WPF)的高级功能,这些功能可在 Internet 区域权限集的限制内安全使用。

表 1:在部分信任中安全的 WPF 特性

功能区域 功能 / 特点
概况 浏览器窗口

源访问站点

IsolatedStorage (512KB 限制)

UIAutomation 供应器

指挥

输入法编辑器(IME)

平板电脑触笔和墨迹

使用鼠标捕获与移动事件来模拟拖放操作

OpenFileDialog

XAML 反序列化(通过 XamlReader.Load)
Web 集成 浏览器下载对话框

Top-Level User-Initiated 导航

mailto:links

统一资源标识符参数

HTTPWebRequest

IFRAME 中托管的 WPF 内容

使用 Frame 托管 Same-Site HTML 页面

使用 WebBrowser 托管同一网站 HTML 页面

Web 服务 (ASMX)

Web 服务(使用 Windows Communication Foundation)

脚本编写

文档对象模型
视觉元素 2D 和 3D

动画

媒体(源站和跨域)

图像处理/音频/视频
读取 FlowDocuments

XPS 文档

嵌入式字体和系统字体

CFF 和 TrueType 字体
编辑 拼写检查

RichTextBox

纯文本和墨迹剪贴板支持

User-Initiated 粘贴

复制所选内容
控件 常规控件

下表概括介绍了 WPF 的高层次功能。 有关更多详细信息,Windows SDK 记录 WPF 中每个成员所需的权限。 此外,以下功能还包含有关部分信任执行的更多详细信息,包括特殊注意事项。

下表概述了在 Internet 区域权限集限制内无法安全运行的 WPF 功能。

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

功能区域 功能 / 特点
概况 窗口(应用程序定义的 Windows 和对话框)

保存文件对话框

文件系统

注册表访问

拖放

XAML 序列化(通过 XamlWriter.Save)

UIAutomation 客户端

源窗口访问 (HwndHost)

完整语音支持

Windows 窗体互作性
视觉元素 位图效果

图像编码
编辑 富文本格式剪贴板

完整的 XAML 支持

部分信任编程

对于 XBAP 应用程序,超过默认权限集的代码将具有不同的行为,具体取决于安全区域。 在某些情况下,用户在尝试安装它时会收到警告。 用户可以选择继续或取消安装。 下表描述了每个安全区域的应用程序的行为,以及应用程序必须执行的作才能接收完全信任。

警告

XBAP 要求旧版浏览器运行,例如 Internet Explorer 和旧版 Firefox。 这些较旧的浏览器通常在 Windows 10 和 Windows 11 上不受支持。 由于安全风险,新式浏览器不再支持 XBAP 应用所需的技术。 不再支持启用 XBAP 的插件。 有关详细信息,请参阅 有关 WPF 浏览器托管应用程序(XBAP)的常见问题解答。

安全区域 行为 获取完全信任
本地计算机 自动完全信任 无需执行任何操作。
Intranet 和受信任的站点 提示提供完全信任 使用证书对 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 封装此行为,并根据情况返回 truefalse

功能正常降级

能够检测代码是否拥有权限去执行它需要进行的操作,对于可从不同区域运行的代码来说是很重要的。 虽然检测区域是一回事,但最好为用户提供替代方法(如果可能)。 例如,完全信任应用程序通常允许用户在所需的任何位置创建文件,而部分信任应用程序只能在独立存储中创建文件。 如果创建文件的代码存在于由完全信任(独立)应用程序和部分信任(浏览器托管)应用程序共享的程序集中,并且这两个应用程序都希望用户能够创建文件,则共享代码应检测它在适当位置创建文件之前是否在部分或完全信任中运行。 以下代码演示了这两者。

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)仅在 Internet 区域沙盒中运行,则可以使用此属性 BrowserInteropHelper.IsBrowserHosted ,该属性对于 XAML 浏览器应用程序(XBAP)返回 true。

警告

XBAP 要求旧版浏览器运行,例如 Internet Explorer 和旧版 Firefox。 这些较旧的浏览器通常在 Windows 10 和 Windows 11 上不受支持。 由于安全风险,新式浏览器不再支持 XBAP 应用所需的技术。 不再支持启用 XBAP 的插件。 有关详细信息,请参阅 有关 WPF 浏览器托管应用程序(XBAP)的常见问题解答。

注释

IsBrowserHosted 仅区分应用程序是否在浏览器中运行,而不是应用程序运行的权限集。

管理权限

默认情况下,XBAP 以部分信任(默认 Internet 区域权限集)运行。 但是,根据应用程序的要求,可以从默认值更改权限集。 例如,如果从本地 Intranet 启动 XBAP,则可以利用增加的权限集,如下表所示。

警告

XBAP 要求旧版浏览器运行,例如 Internet Explorer 和旧版 Firefox。 这些较旧的浏览器通常在 Windows 10 和 Windows 11 上不受支持。 由于安全风险,新式浏览器不再支持 XBAP 应用所需的技术。 不再支持启用 XBAP 的插件。 有关详细信息,请参阅 有关 WPF 浏览器托管应用程序(XBAP)的常见问题解答。

表 3:LocalIntranet 和 Internet 权限

许可 特征 LocalIntranet 互联网
DNS(域名系统) 访问 DNS 服务器 是的
环境变量 读取 是的
文件对话框 开放 是的 是的
文件对话框 非受限 是的
独立存储 用户程序集隔离 是的
独立存储 未知隔离 是的 是的
独立存储 无限制的用户配额 是的
媒体 安全音频、视频和图像 是的 是的
印刷 默认打印 是的
印刷 安全打印 是的 是的
反射 发出 是的
安全 托管代码执行 是的 是的
安全 断言授予的权限 是的
用户界面 非受限 是的
用户界面 安全顶级窗口 是的 是的
用户界面 自己的剪贴板 是的 是的
浏览器 安全框架导航到 HTML 是的 是的

注释

仅当用户启动时,才允许在部分信任中剪切和粘贴。

如果需要增加权限,则需要更改项目设置和 ClickOnce 应用程序清单。 有关详细信息,请参阅 WPF XAML 浏览器应用程序概述。 以下文档可能也很有帮助。

如果 XBAP 需要完全信任,则可以使用相同的工具来增加请求的权限。 尽管 XBAP 仅在本地计算机、Intranet 或浏览器受信任或允许的站点中列出的 URL 上安装并启动时才会收到完全信任。 如果应用程序是从 Intranet 或受信任的站点安装的,用户将收到标准 ClickOnce 提示,通知他们提升的权限。 用户可以选择继续或取消安装。

或者,可以使用 ClickOnce 受信任的部署模型从任何安全区域进行完全信任部署。 有关详细信息,请参阅受信任的应用程序部署概述和安全性

另请参阅