安全 Windows 应用开发简介

这篇介绍性文章可帮助应用架构师和开发人员更好地了解 Windows 10 平台的各种功能,这些功能可以加速创建安全的通用 Windows 平台 (UWP) 应用。 其中详细介绍了如何在以下每个阶段使用 Windows 安全功能:身份验证、动态数据和静态数据。 通过查看每个章节中包含的其他资源,可以找到有关每个主题的更深入的信息。

1 简介

开发一个安全的应用可能是一个挑战。 在当今这个移动、社交、云和复杂企业应用的快节奏世界中,客户希望应用能够比以往更快地可用和更新。 他们还使用许多类型的设备,进一步增加了创建应用体验的复杂性。 如果你是针对 Windows 10 和 Windows 11 通用 Windows 平台 (UWP) 开发产品,那么这可能包括传统的台式机、笔记本电脑、平板电脑和移动设备;此外还有越来越多的新设备,包括物联网、Xbox One、Microsoft Surface Hub 和 HoloLens。 作为开发人员,必须确保应用在所有相关平台或设备上安全地通信和存储数据。

下面是使用 Windows 10 和 Windows 11 安全功能的一些优势。

  • 通过为安全组件和技术使用一致的 API,将在所有支持 Windows 10 和 Windows 11 的设备上实现标准化的安全性。
  • 与实现自定义代码以覆盖这些安全方案相比,编写、测试和维护的代码更少。
  • 你的应用变得更加稳定和安全,因为你使用操作系统来控制应用如何访问其资源以及本地或远程系统资源。

在身份验证过程中,会验证请求访问特定服务的用户的身份。 Windows Hello 是 Windows 10 和 Windows 11 中的组件,可帮助在 Windows 应用中创建更安全的身份验证机制。 借助它,你可以使用个人标识号 (PIN) 或用户指纹、人脸或虹膜等生物特征为应用实现多重身份验证。

动态数据指的是连接和通过它传输的信息。 例如,使用 Web 服务从远程服务器检索数据。 安全套接字层 (SSL) 和安全超文本传输协议 (HTTPS) 的使用确保了连接的安全性。 防止中间方访问这些消息或防止未经授权的应用与 Web 服务通信,是确保动态数据数据安全的关键。

最后,静态数据与驻留在内存或存储介质上的数据相关。 Windows 10 和 Windows 11 具有一个应用模型,可阻止应用之间的未经授权的数据访问,并提供加密 API 来进一步保护设备上的数据。 可以使用名为凭据保险箱的功能在设备上安全地存储用户凭据,操作系统会阻止其他应用访问访问这些凭据。

2 身份验证因素

为了保护数据,必须标识请求访问数据的人,并授权其访问他们请求的数据资源。 标识用户的过程称为身份验证,确定对资源的访问权限称为授权。 这些是密切相关的操作,对于用户来说,它们可能难以区分。 它们可以是相对简单的操作,也可以是复杂的操作,这取决于许多因素:例如,数据是驻留在一台服务器上还是分布在多个系统中。 提供身份验证和授权服务的服务器称为标识提供者。

为了使用特定服务和/或应用自行进行身份验证,用户使用由他们知道的内容、他们拥有的内容和/或他们的相关内容组成的凭据。 其中每一个都被称为身份验证因素。

  • 用户知道的内容通常是密码,但也可以是个人标识号 (PIN) 或“机密”问答对。
  • 用户拥有的内容通常是硬件内存设备,例如包含用户唯一的身份验证数据的 U 盘。
  • 用户相关内容通常包含其指纹,但用户语音、面部、眼部(眼睛)特征或行为模式等是越来越受欢迎的因素。 当作为数据存储时,这些测量结果被称为生物特征。

用户创建的密码本身就是一个身份验证因素,但这通常是不够的;任何知道密码的人都可以冒充拥有密码的用户。 智能卡可以提供更高级别的安全性,但可能会被盗、丢失或放错地方。 一个可以通过指纹或眼部扫描对用户进行身份验证的系统可能会提供最高且最方便的安全级别,但它需要昂贵且专业的硬件(例如,用于面部识别的 Intel RealSense 相机),而这可能不是所有用户都能用的。

设计系统使用的身份验证方法是数据安全的一个复杂而重要的方面。 通常,在身份验证中使用的因素越多,系统就越安全。 同时,身份验证必须可用。 用户通常一天会登录很多次,所以这个过程必须很快。 对身份验证类型的选择需要在安全性和易用性之间进行权衡;单因素身份验证最不安全且最容易使用;而多重身份验证变得更安全,但随着因素的增加,会变得更复杂。

2.1 单因素身份验证

这种形式的身份验证基于单个用户凭据。 这通常是一个密码,但也可能是一个个人标识号 (PIN)。

以下是单因素身份验证的过程。

  • 用户将其用户名和密码提供给标识提供者。 标识提供者是验证用户标识的服务器进程。
  • 标识提供者检查用户名和密码是否与系统中存储的用户名和密码相同。 在大多数情况下,密码将被加密,从而提供额外的安全性,使其他人无法读取。
  • 标识提供者返回一个身份验证状态,该状态指示身份验证是否成功。
  • 如果成功,则开始数据交换。 如果失败,则必须重新对用户进行身份验证。

single-factor authentication

目前,这种身份验证方法是服务中最常用的身份验证方法。 当用作唯一的身份验证手段时,它也是最不安全的身份验证形式。 密码复杂性要求、“机密问题”和定期密码更改可能会使使用密码更安全,但他们给用户带来了更大的负担,而且对黑客也没有有效的威慑作用。

密码的挑战在于,与具有多个因素的系统相比,成功猜出密码更容易。 如果他们从一个小网店窃取了一个包含用户账户和哈希密码的数据库,就可以使用其他网站上使用的密码。 用户倾向于一直重复使用帐户,因为复杂的密码很难记住。 对于 IT 部门,管理密码也带来了必须提供重置机制的复杂性,需要频繁更新密码,并以安全的方式存储密码。

尽管存在种种缺点,但单因素身份验证让用户可以控制凭据。 它们创建并修改它,并且身份验证过程只需要键盘。 这是区分单因素身份验证和多重身份验证的主要方面。

2.1.1 Web 身份验证代理

如前所述,IT 部门密码身份验证的挑战之一是管理用户名/密码的基数、重置机制等方面的额外开销。一种越来越流行的选择是依赖第三方标识提供者,该提供者通过 OAuth(一种开放的身份验证标准)提供身份验证。

使用 OAuth,IT 部门可以有效地将维护包含用户名和密码的数据库、重置密码功能等的复杂性“外包”给 Facebook、X 或 Microsoft 等第三方标识提供者。

用户可以完全控制他们在这些平台上的标识,但在用户经过身份验证并征得他们的同意后,应用可以向提供者请求令牌,该令牌可用于授权经过身份验证的用户。

Windows 10 和 Windows 11 中的 Web 身份验证代理为应用提供了一组 API 和基础结构,用于使用 OAuth 和 OpenID 等身份验证和授权协议。 应用可以通过 WebAuthenticationBroker API 启动身份验证操作,从而返回 WebAuthenticationResult。 通信流程概述如下图所示。

wab workflow

应用充当代理,通过应用中的 WebView 启动与标识提供者的身份验证。 当标识提供者对用户进行身份验证时,它会向应用返回一个令牌,该令牌可用于从标识提供者请求有关用户的信息。 作为一项安全措施,应用必须在标识提供者处注册,然后才能与标识提供者代理身份验证过程。 每个提供者的注册步骤不同。

下面是用于调用 WebAuthenticationBroker API 以与提供者通信的常规工作流。

  • 构造要发送到标识提供者的请求字符串。 每个 Web 服务的字符串数以及每个字符串中的信息都不同,但通常包括两个 URI 字符串,每个字符串都包含一个 URL:一个是发送身份验证请求的字符串,另一个是授权完成后用户重定向到的字符串。
  • 调用 WebAuthenticationBroker.AuthenticateAsync,传入请求字符串,并等待标识提供者的响应。
  • 调用 WebAuthenticationResult.ResponseStatus,以获取收到响应时的状态。
  • 如果通信成功,请处理标识提供者返回的响应字符串。 如果失败,请处理错误。

如果通信成功,请处理标识提供者返回的响应字符串。 如果失败,请处理错误。

下面是用于此过程的示例 C# 代码。 有关信息和详细演练,请参阅 WebAuthenticationBroker。 有关完整的代码示例,请查看 GitHub 上的 WebAuthenticationBroker 示例

string startURL = "https://<providerendpoint>?client_id=<clientid>";
string endURL = "http://<AppEndPoint>";

var startURI = new System.Uri(startURL);
var endURI = new System.Uri(endURL);

try
{
    WebAuthenticationResult webAuthenticationResult = 
        await WebAuthenticationBroker.AuthenticateAsync( 
            WebAuthenticationOptions.None, startURI, endURI);

    switch (webAuthenticationResult.ResponseStatus)
    {
        case WebAuthenticationStatus.Success:
            // Successful authentication. 
            break;
        case WebAuthenticationStatus.ErrorHttp:
            // HTTP error. 
            break;
        default:
            // Other error.
        break;
    }
}
catch (Exception ex)
{
    // Authentication failed. Handle parameter, SSL/TLS, and
    // Network Unavailable errors here. 
}

2.2 多重身份验证

多重身份验证使用多个身份验证因素。 通常,“你知道的内容”(如密码)与“你拥有的内容”相结合,后者可以是手机或智能卡。 即使攻击者发现了用户的密码,如果没有设备或卡,帐户仍然无法访问。 如果只有设备或卡被泄露,那么对于没有密码的攻击者来说是没有用的。 因此,多重身份验证比单因素身份验证更安全,但也更复杂。

使用多重身份验证的服务通常会让用户选择如何接收第二个凭据。 这种类型的认证的一个例子是一种常用的过程,其中使用短信将验证码发送到用户的移动电话。

  • 用户将其用户名和密码提供给标识提供者。
  • 标识提供者按照单因素授权的方式验证用户名和密码,然后查找存储在系统中的用户手机号码。
  • 服务器向用户的移动电话发送包含生成的验证码的短信。
  • 用户向标识提供者提供验证码;通过呈现给用户的表格。
  • 标识提供者返回一个身份验证状态,指示这两个凭据的身份验证是否成功。
  • 如果成功,则开始数据交换。 否则,必须重新对用户进行身份验证。

two-factor authentication

正如你所看到的,这个过程也不同于单因素身份验证,因为第二个用户凭据是发送给用户的,而不是由用户创建或提供的。 因此,用户不能完全控制必要的凭据。 当智能卡被用作第二个凭据时,这也适用:组织负责创建并提供给用户。

2.2.1 Azure Active Directory

Azure Active Directory (Azure AD) 是一种基于云的标识和访问管理服务,可以作为单因素或多重身份验证中的标识提供者。 Azure AD 身份验证可以使用验证码,也可以不使用验证码。

虽然 Azure AD 也可以实现单因素身份验证,但企业通常需要更高的多重身份验证安全性。 在多重身份验证配置中,使用 Azure AD 帐户进行身份验证的用户可以选择将验证码作为短信发送到他们的手机或 Azure Authenticator 移动应用。

此外,Azure AD 可用作 OAuth 提供程序,为标准用户提供跨各种平台的应用的身份验证和授权机制。 若要了解详细信息,请参阅 Azure Active DirectoryAzure 上的多重身份验证

2.4 Windows Hello

在 Windows 10 和 Windows 11 中,操作系统中内置了一种便捷的多重身份验证机制。 Windows Hello 是内置于 Windows 10 和 Windows 11 中的新生物特征登录系统。 由于它直接内置于操作系统中,因此 Windows Hello 允许人脸或指纹识别解锁用户的设备。 Windows 安全凭据存储保护设备上的生物特征数据。

Windows Hello 为设备识别单个用户提供了一种强大的方法,它解决了用户与请求的服务或数据项之间的第一部分路径。 在设备识别出用户之后,在确定是否授予对所请求资源的访问权限之前,它仍然必须对用户进行身份验证。 Windows Hello 还提供了强大的双因素身份验证 (2FA),该身份验证完全集成到 Windows 中,并用特定设备和生物识别手势或 PIN 的组合取代了可重复使用的密码。 PIN 由用户指定,作为其 Microsoft 帐户注册的一部分。

不过,Windows Hello 不仅仅是传统 2FA 系统的替代品。 从概念上讲,它类似于智能卡:身份验证是使用加密基元而不是字符串比较执行的,并且用户的密钥材料在防篡改硬件内部是安全的。 Microsoft Hello 也不需要部署智能卡所需的额外基础结构组件。 特别是,如果目前没有公钥基础结构 (PKI),则不需要 PKI 来管理证书。 Windows Hello 结合了智能卡的主要优势(虚拟智能卡的部署灵活性和物理智能卡的可靠安全性),没有任何缺点。

用户必须先向 Windows Hello 注册设备,然后才能使用该设备进行身份验证。 Windows Hello 使用非对称(公钥/私钥)加密,其中一方使用公钥来加密另一方可以使用私钥解密的数据。 对于 Windows Hello,它将创建一组公钥/私钥对,并将私钥写入设备的受信任平台模块 (TPM) 芯片。 注册设备后,UWP 应用可以调用系统 API 来检索用户的公钥,该公钥可用于在服务器上注册用户。

应用的注册工作流可能如下所示:

windows hello registration

你收集的注册信息可能比在这个简单的方案中包含更多的识别信息。 例如,如果应用访问安全服务(例如银行服务),则需要在注册过程中请求身份证明和其他事项。 满足所有条件后,此用户的公钥将存储在后端,并用于在用户下次使用服务时进行验证。

有关 Windows Hello 的详细信息,请参阅 Windows Hello 指南Windows Hello 开发人员指南

3 动态数据安全方法

动态数据安全方法适用于连接到网络的设备之间的传输数据。 数据可以在专用企业 Intranet 的高安全环境上的系统之间传输,也可以在 Web 的不安全环境中客户端和 Web 服务之间传输。 Windows 10 和 Windows 11 应用通过其网络 API 支持 SSL 等标准,并使用 Azure API 管理等技术合作,开发人员可以通过这些技术确保其应用的适当安全级别。

3.1 远程系统身份验证

与远程计算机系统进行通信的一般情况有两种。

  • 本地服务器通过直接连接对用户进行身份验证。 例如,当服务器和客户端位于公司 Intranet 上时。
  • Web 服务通过 Internet 进行通信。

Web 服务通信的安全要求高于直接连接方案中的安全要求,因为数据不再是安全网络的一部分,而且恶意攻击者试图拦截数据的可能性也更高。 由于各种类型的设备将访问该服务,因此它们可能会生成为 RESTful 服务,而不是 WCF,例如,这意味着对服务的身份验证和授权也会带来新的挑战。 我们将讨论安全远程系统通信的两个要求。

第一个要求是消息保密性:客户端和 Web 服务之间传递的信息(例如,用户标识和其他个人信息)在传输过程中不得被第三方读取。 这通常是通过加密消息发送的连接和加密消息本身来实现的。 在私钥/公钥加密中,公钥可供任何人使用,用于加密要发送到特定接收方的消息。 私钥仅由接收方保存,用于解密消息。

第二个要求是消息完整性:客户端和 Web 服务必须能够验证他们收到的消息是打算由另一方发送的消息,并且消息在传输过程中没有被更改。 这可以通过使用数字签名和证书身份验证对消息进行签名来实现。

3.2 个 SSL 连接

为了建立和维护与客户端的安全连接,Web 服务可以使用安全超文本传输协议 (HTTPS) 支持的安全套接字层 (SSL)。 SSL 通过支持公钥加密以及服务器证书来提供消息保密性和完整性。 SSL 被传输层安全性 (TLS) 所取代,但 TLS 通常被随意称为 SSL。

当客户端请求访问服务器上的资源时,SSL 会启动与服务器的协商过程。 这称为 SSL 握手。 加密级别、一组公钥和私钥,以及客户端和服务器证书中的标识信息作为 SSL 连接期间的所有通信的基础。 服务器此时还可能要求对客户端进行身份验证。 一旦建立了连接,所有消息都会使用协商的公钥进行加密,直到连接关闭。

3.2.1 SSL 固定

虽然 SSL 可以使用加密和证书提供消息机密性,但它不执行任何操作来验证客户端通信的服务器是否正确。 未经授权的第三方可以模仿服务器的行为,拦截客户端传输的敏感数据。 为了防止这种情况发生,使用了一种名为 SSL 固定的技术来验证服务器上的证书是否是客户端期望和信任的证书。

可通过几种不同的方法在应用中实现 SSL 固定,每个方法都有自己的优点和缺点。 最简单的方法是在应用的包清单中通过证书声明。 此声明使应用包能够安装数字证书并指定对这些证书的独占信任。 这导致只允许在应用程序和证书链中具有相应证书的服务器之间进行 SSL 连接。 此机制还允许安全使用自签名证书,因为不需要依赖于受信任的公共证书颁发机构的第三方。

ssl manifest

为了更好地控制验证逻辑,API 可用于验证服务器响应 HTTPS 请求返回的证书。 请注意,此方法需要发送请求并检查响应,因此在实际发送请求中的敏感信息之前,请务必将其添加为验证。

下面的 C# 代码说明了这种 SSL 固定方法。 ValidateSSLRoot 方法使用 HttpClient 类执行 HTTP 请求。 客户端发送响应后,使用 RequestMessage.TransportInformation.ServerIntermediateCertificates 集合检查服务器返回的证书。 然后,客户端可以使用包含的指纹验证整个证书链。 此方法不要求在服务器证书过期并续订时在应用中更新证书指纹。

private async Task ValidateSSLRoot()
{
    // Send a get request to Bing
    var httpClient = new HttpClient();
    var bingUri = new Uri("https://www.bing.com");
    HttpResponseMessage response = 
        await httpClient.GetAsync(bingUri);

    // Get the list of certificates that were used to
    // validate the server's identity
    IReadOnlyList<Certificate> serverCertificates = response.RequestMessage.TransportInformation.ServerIntermediateCertificates;
  
    // Perform validation
    if (!ValidateCertificates(serverCertificates))
    {
        // Close connection as chain is not valid
        return;
    }
    // Validation passed, continue with connection to service
}

private bool ValidateCertificates(IReadOnlyList<Certificate> certs)
{
    // In this example, we iterate through the certificates
    // and check that the chain contains
    // one specific certificate we are expecting
    foreach (var cert in certs)
    {
        byte[] thumbprint = cert.GetHashValue();

        // Check if the thumbprint matches whatever you 
        // are expecting
        var expected = new byte[] { 212, 222, 32, 208, 94, 102, 
            252, 83, 254, 26, 80, 136, 44, 120, 219, 40, 82, 202, 
            228, 116 };

        // ThumbprintMatches does the byte[] comparison 
        if (ThumbprintMatches(thumbprint, expected))
        {
            return true;
        }
    }
    return false;
}

3.3 发布和保护对 REST API 的访问

为了确保对 Web 服务的授权访问,每次进行 API 调用时,都必须要求进行身份验证。 当 Web 服务在整个 Web 中公开时,能够控制性能和规模也是需要考虑的问题。 Azure API 管理是一项可以帮助在 Web 上公开 API 的服务,同时提供三个级别的功能。

API 的发布者/管理员可以通过 Azure API 管理的发布者门户轻松配置 API。 在这里,可以创建 API集,并且可以管理对它们的访问,以控制谁有权访问哪些 API。

希望访问这些 API 的开发人员可以通过开发人员门户发出请求,该门户可以立即提供访问权限,也可以要求发布者/管理员批准。 开发人员还可以在开发人员门户中查看 API 文档和示例代码,以快速采用 Web 服务提供的 API。

这些开发人员创建的应用随后通过 Azure API 管理提供的代理访问 API。 代理提供了一个模糊层,隐藏了发布者/管理员服务器上 API 的实际端点,也可以包括诸如 API 转换之类的附加逻辑,以确保当对一个 API 的调用重定向到另一个 API 时,公开的 API 保持一致。 它还可以使用 IP 筛选来阻止源自特定 IP 域或一组域的 API 调用。 Azure API 管理还使用一组公钥(称为 API 密钥)对每个 API 调用进行身份验证和授权,从而保护其 Web 服务的安全。 当授权失败时,对 API 及其支持的功能的访问将被阻止。

Azure API管理还可以减少对服务的 API 调用次数(称为节流的过程),以优化 Web 服务的性能。 若要了解详细信息,请查看 AzureCon 2015 上的 Azure API 管理和 Azure API 管理。

4 静态数据安全方法

数据到达设备时,我们将其称为“静态数据”。此数据需要以安全方式存储在设备上,以便未经授权的用户或应用无法访问它。 Windows 10 和 Windows 11 中的应用模型做了很多工作,以确保任何应用存储的数据只能被该应用访问,同时在必要时提供 API 来共享数据。 还提供了其他 API,以确保数据可以加密,凭据可以安全存储。

4.1 Windows 应用模型

传统上,Windows 从未对应用有过定义。 它通常被称为可执行文件 (.exe),这从未包括安装、状态存储、执行长度、版本控制、操作系统集成或应用到应用的通信。 通用 Windows 平台模型定义了一个应用模型,该模型涵盖安装、运行时环境、资源管理、更新、数据模型和卸载。

Windows 10 应用在容器中运行,这意味着默认情况下它们具有有限的权限(用户可以请求和授予额外的权限)。 例如,如果应用想要访问系统上的文件,则必须使用 Windows.Storage.Pickers 命名空间中的文件选取器,让用户选取文件(未启用直接访问文件)。 另一个示例是,如果应用想要访问用户的位置数据,则需要启用位置设备功能,并在下载时提示用户,此应用将请求访问用户的位置。 除此之外,应用首次想要访问用户的位置时,会向用户显示额外的同意提示,请求访问数据的权限。

请注意,此应用模型充当了应用的“监狱”,这意味着它们无法到达外面,但它不是一个不能从外面到达的“城堡”(拥有管理员权限的应用当然仍然可以到达里面)。 Windows 10 和 Windows 11 中的 Device Guard 可让组织/IT 指定允许执行哪些 (Win32) 应用,这进一步有助于限制此访问。

应用模型还管理应用生命周期。 例如,默认情况下,它会限制应用的后台执行;一旦应用进入后台,在给应用一段短暂的时间以解决代码中的应用挂起问题后,该过程就会被挂起,其内存也会被冻结。 操作系统确实为应用提供要求执行特定后台任务的机制(按计划执行,由 Internet/蓝牙连接、电源更改等各种事件触发),以及特定方案(如音乐播放或 GPS 跟踪)。

当设备上的内存资源不足时,Windows 会通过终止应用来释放内存空间。 此生命周期模型强制应用在挂起时保留数据,因为暂停和终止之间没有额外的时间。

有关详细信息,请参阅通用:了解 Windows 10/11 应用程序的生命周期

4.2 存储的凭据保护

访问经过身份验证服务的 Windows 应用通常为用户提供在本地设备上存储其凭据的选项。 这对用户来说很方便;当他们提供用户名和密码时,应用会在随后的应用启动中自动使用它们。 由于如果攻击者获得此存储数据的访问权限,则 Windows 10 和 Windows 11 可能会带来安全问题,因此 Windows 应用提供了将用户凭据存储在安全凭据库中的能力。 应用调用凭据保险箱 API 来存储和检索保险箱中的凭据,而不是将它们存储在应用的存储容器中。 凭据保险箱由操作系统管理,但访问仅限于存储凭据的应用,从而为凭据存储提供了一个安全管理的解决方案。

当用户提供要存储的凭据时,应用将使用 Windows.Security.Credentials 命名空间中的 PasswordVault 对象获取对凭保险箱的引用。 然后,它创建一个 PasswordCredential 对象,其中包含 Windows 应用的标识符和用户名和密码。 这会传递到 PasswordVault.Add 方法,用于将凭据存储在保险箱中。 下面的 C# 代码示例演示如何完成以上过程。

var vault = new PasswordVault();
vault.Add(new PasswordCredential("My App", username, password));

在以下 C# 代码示例中,应用通过调用 PasswordVault 对象的 FindAllByResource 方法请求与应用对应的所有凭据。 如果返回多个,则会提示用户输入用户名。 如果凭据不在保险箱中,应用会提示用户输入凭据。 然后,用户使用凭据登录到服务器。

private string resourceName = "My App";
private string defaultUserName;

private void Login()
{
    PasswordCredential loginCredential = GetCredentialFromLocker();

    if (loginCredential != null)
    {
        // There is a credential stored in the locker.
        // Populate the Password property of the credential
        // for automatic login.
        loginCredential.RetrievePassword();
    }
    else
    {
        // There is no credential stored in the locker.
        // Display UI to get user credentials.
        loginCredential = GetLoginCredentialUI();
    }
    // Log the user in.
    ServerLogin(loginCredential.UserName, loginCredential.Password);
}

private PasswordCredential GetCredentialFromLocker()
{
    PasswordCredential credential = null;

    var vault = new PasswordVault();

    IReadOnlyList<PasswordCredential> credentialList = null;

    try
    {
        credentialList = vault.FindAllByResource(resourceName);
    }
    catch(Exception)
    {
        return null;
    }

    if (credentialList.Count == 1)
    {
        credential = credentialList[0];
    }
    else if (credentialList.Count > 0)
    {
        // When there are multiple usernames,
        // retrieve the default username. If one doesn't
        // exist, then display UI to have the user select
        // a default username.
        defaultUserName = GetDefaultUserNameUI();

        credential = vault.Retrieve(resourceName, defaultUserName);
    }
    return credential;
}

有关详细信息,请参阅凭据保险箱

4.3 存储的数据保护

处理存储的数据(通常称为静态数据)时,加密可能会阻止未经授权的用户访问存储的数据。 加密数据的两种常见机制是使用对称密钥或使用非对称密钥。 然而,数据加密无法确保数据在发送和存储之间保持不变。 换句话说,无法确保数据完整性。 使用消息身份验证代码、哈希和数字签名是解决此问题的常见方法。

4.3.1 数据加密

使用对称加密,发送方和收件人都具有相同的密钥,并使用它来加密和解密数据。 这种方法的挑战是安全地共享密钥,以便双方都知道这一点。

对此的一个答案是非对称加密,其中使用了公钥/私钥对。 任何想要加密消息的人都可以自由共享公钥。 私钥始终是保密的,因此只有摸才能使用它来解密数据。 允许发现公钥的一种常见方法是使用数字证书,也称为证书。 证书除了保存有关用户或服务器的信息(如名称、颁发者、电子邮件地址和国家/地区)之外,还保存有关公钥的信息。

Windows 应用开发人员可以使用 SymmetricKeyAlgorithmProviderAsymmetricKeyAlgorithmProvider 类在其 UWP 应用中实现对称和非对称加密。 此外,CryptographicEngine 类还可用于加密和解密数据、对内容签名和验证数字签名。 应用还可以使用 Windows.Security.Cryptography.DataProtection 命名空间中的 DataProtectionProvider 类来加密和解密存储的本地数据。

4.3.2 检测消息篡改(MAC、哈希和签名)

MAC 是使用对称密钥(称为密钥)或消息作为 MAC 加密算法的输入而产生的代码(或标记)。 密钥和算法在消息传输之前由发送方和接收方商定。

MAC 验证如下所示的消息。

  • 发送器通过使用密钥作为 MAC 算法的输入来导出 MAC 标记。
  • 发送方将 MAC 标记和消息发送到接收方。
  • 接收方使用密钥和消息作为 MAC 算法的输入来派生 MAC 标记。
  • 接收方将 MAC 标记与发送方的 MAC 标记进行比较。 如果它们相同,则我们知道消息未被篡改。

mac verification

Windows 应用可以通过调用 MacAlgorithmProvider 类生成密钥,调用CryptographicEngine 类来执行 MAC 加密算法,来实现 MAC 消息验证。

4.3.3 使用哈希

哈希函数是一种加密算法,它获取任意长的数据块,并返回一个称为哈希值的固定大小的位字符串。 有一系列哈希函数可以执行此操作。

在上述消息传输方案中,可以使用哈希值来代替 MAC。 发送方发送哈希值和消息,接收方从发送方的哈希值和消息派生自己的哈希值,并比较这两个哈希值。 在 Windows 10 和 Windows 11 上运行的应用可以调用 HashAlgorithmProvider 类来枚举可用的哈希算法并运行其中一种算法。 CryptographicHash 类表示哈希值。 CryptographicHash.GetValueAndReset 方法可用于重复哈希不同的数据,而无需为每次使用重新创建对象。 CryptographicHash 类的 Append 方法将新数据添加到要进行哈希处理的缓冲区中。 以下 C# 代码示例显示了整个过程。

public void SampleReusableHash()
{
    // Create a string that contains the name of the
    // hashing algorithm to use.
    string strAlgName = HashAlgorithmNames.Sha512;

    // Create a HashAlgorithmProvider object.
    HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(strAlgName);

    // Create a CryptographicHash object. This object can be reused to continually
    // hash new messages.
    CryptographicHash objHash = objAlgProv.CreateHash();

    // Hash message 1.
    string strMsg1 = "This is message 1";
    IBuffer buffMsg1 = CryptographicBuffer.ConvertStringToBinary(strMsg1, BinaryStringEncoding.Utf16BE);
    objHash.Append(buffMsg1);
    IBuffer buffHash1 = objHash.GetValueAndReset();

    // Hash message 2.
    string strMsg2 = "This is message 2";
    IBuffer buffMsg2 = CryptographicBuffer.ConvertStringToBinary(strMsg2, BinaryStringEncoding.Utf16BE);
    objHash.Append(buffMsg2);
    IBuffer buffHash2 = objHash.GetValueAndReset();

    // Convert the hashes to string values (for display);
    string strHash1 = CryptographicBuffer.EncodeToBase64String(buffHash1);
    string strHash2 = CryptographicBuffer.EncodeToBase64String(buffHash2);
}

4.3.4 数字签名

数字签名存储消息的数据完整性以类似于 MAC 身份验证的方式进行验证。 下面是数字签名工作流的运行方式。

  • 发送方通过使用消息作为哈希算法的输入来派生哈希值(也称为摘要)。
  • 发送方使用其私钥对摘要进行加密。
  • 发送方发送消息、加密摘要以及所使用的哈希算法的名称。
  • 接收方使用公钥解密收到的加密摘要。 然后,它使用哈希算法对消息进行哈希处理,以创建其自己的摘要。 最后,接收方比较了两个摘要(它接收和解密的摘要,以及它生成的摘要)。 只有当两者匹配时,接收方才能确保消息是由私钥拥有者发送的,因此他们就是他们所说的自己,并且消息在传输过程中没有被更改。

digital signatures

哈希算法非常快,因此即使是大型消息也可以快速派生哈希值。 生成的哈希值是任意长度,并且可能比完整消息短,因此使用公钥和私钥仅加密和解密摘要而不是完整消息是一种优化。

有关详细信息,请参阅有关数字签名MAC、哈希和签名以及加密的文章。

5 摘要

Windows 10 和 Windows 11 中的通用 Windows 平台提供了多种方法来利用操作系统功能创建更安全的应用。 在不同的身份验证方案中,例如使用 OAuth 标识提供者的单因素、多重身份验证或代理身份验证,存在 API 来缓解身份验证最常见的难题。 Windows Hello 提供了一种新的生物特征登录系统,可以识别用户,并主动挫败绕过正确身份识别的努力。 它还提供多层密钥和证书,这些密钥和证书永远不会在受信任的平台模块外部显示或使用。 此外,通过可选地使用证明标识密钥和证书,还提供了另一层安全性。

为了确保动态数据的安全,API 通过 SSL 与远程系统安全通信,同时提供了通过 SSL 固定验证服务器真实性的可能性。 Azure API管理通过提供强大的配置选项来帮助以安全且受控的方式发布 API,该配置选项用于使用提供 API 端点的附加模糊处理的代理在 Web 上公开 API。 通过使用 API 密钥来保护对这些 API 的访问,并且可以限制 API 调用以控制性能。

当数据到达设备时,Windows 应用模型可以更好地控制应用的安装方式、更新和访问数据的方式,同时防止它以未经授权的方式访问其他应用的数据。 凭据保险箱可以提供由操作系统管理的用户凭据的安全存储,并且可以通过使用通用 Windows 平台提供的加密和哈希 API 来保护设备上的其他数据。

6 资源

6.1 操作指南文章

6.2 示例代码

6.3 API 参考