并非所有正在创建 ClickOnce 部署的开发人员都计划自行部署应用程序。 他们中的许多人只是使用 ClickOnce 打包应用程序,然后将文件交给客户,例如大型公司。 客户将成为负责在其网络上托管应用程序的主体。 本主题讨论在版本 3.5 之前的 .NET Framework 版本中此类部署固有的一些问题。 然后,它描述了通过使用 .NET Framework 3.5 中新的“用于信任的清单”功能而提供的一种新解决方案。 最后,它总结了为仍在使用旧版 .NET Framework 的客户创建 ClickOnce 部署的建议策略。
为客户创建部署时所遇到的问题
计划向客户提供部署时,会出现多个问题。 第一个问题涉及代码签名。 若要跨网络部署,ClickOnce 部署的部署清单和应用程序清单必须使用数字证书进行签名。 这引发了在对清单进行签名时是使用开发人员证书还是客户证书的问题。
要使用哪个证书至关重要,因为 ClickOnce 应用程序的标识基于部署清单的数字签名。 如果开发人员签署部署清单,如果客户是一家大型公司,并且公司的多个部门部署了自定义版本的应用程序,则可能会导致冲突。
例如,假设 Adventure Works 有一个财务部门和一个人力资源部门。 两个部门都从 Microsoft Corporation 许可 ClickOnce 应用程序,该应用程序从存储在 SQL 数据库中的数据生成报表。 Microsoft为每个部门提供为其数据自定义的应用程序版本。 如果应用程序使用相同的 Authenticode 证书进行签名,则尝试使用这两个应用程序的用户会遇到错误,因为 ClickOnce 会将第二个应用程序视为与第一个应用程序相同。 在这种情况下,客户可能会遇到不可预知和不需要的副作用,包括应用程序本地存储的任何数据丢失。
与代码签名相关的另一个问题是部署清单中的 deploymentProvider 元素,该元素告知 ClickOnce 在何处查找应用程序更新。 必须先将此元素添加到部署清单,然后才能对其进行签名。 如果之后添加此元素,则必须重新签名部署清单。
要求客户对部署清单进行签名
解决此问题的一个非唯一部署的解决方案是让开发人员对应用程序清单进行签名,客户对部署清单进行签名。 虽然此方法有效,但它引入了其他问题。 由于 Authenticode 证书必须保持受保护资产,因此客户不能只向开发人员提供证书来对部署进行签名。 虽然客户可以使用 .NET Framework SDK 免费提供的工具自行对部署清单进行签名,但这可能需要比客户愿意或能够提供的更多技术知识。 在这种情况下,开发人员通常会创建应用程序、网站或其他机制,客户可以通过该机制提交其应用程序的版本进行签名。
客户签名对 ClickOnce 应用程序安全性的影响
即使开发人员和客户同意客户应对应用程序清单进行签名,这也会引发有关应用程序标识的其他问题,尤其是在它适用于受信任的应用程序部署时。 (有关此功能的详细信息,请参阅 受信任的应用程序部署概述。假设 Adventure Works 想要配置其客户端计算机,以便Microsoft Corporation 提供的任何应用程序都完全信任运行。 如果 Adventure Works 对部署清单进行签名,则 ClickOnce 将使用 Adventure Work 的安全签名来确定应用程序的信任级别。
使用应用程序清单创建客户部署以提高信任度
.NET Framework 3.5 中的 ClickOnce 包含一项新功能,为开发人员和客户提供了一种全新的解决方案,以解决清单签名问题。 ClickOnce 应用程序清单支持一个名为 <useManifestForTrust> 的新元素,它使开发人员能够表示应用程序清单的数字签名应用于做出信任决策。 开发人员使用 ClickOnce 打包工具(如 Mage.exe、 MageUI.exe和 Visual Studio)将此元素包含在应用程序清单中,以及在清单中嵌入其发布者名称和应用程序名称。
使用 <useManifestForTrust>时,部署清单不必使用证书颁发机构颁发的 Authenticode 证书进行签名。 相反,可以使用所谓的自签名证书对其进行签名。 客户或开发人员使用标准 .NET Framework SDK 工具生成自签名证书,然后使用标准 ClickOnce 部署工具应用于部署清单。 有关详细信息,请参阅 MakeCert。
对部署清单使用自签名证书具有多种优势。 客户无需获取或创建自己的 Authenticode 证书, <useManifestForTrust> 从而简化客户的部署,同时允许开发人员在应用程序中维护自己的品牌标识。 结果是一组更安全且具有唯一的应用程序标识的已签名部署。 这消除了将同一应用程序部署到多个客户时可能发生的潜在冲突。
有关启用<useManifestForTrust>的 ClickOnce 部署的分步信息,请参阅 演练:手动部署不需要重新签名且保留品牌信息的 ClickOnce 应用程序。
运行时信任的应用程序清单的工作原理
若要更好地了解在运行时如何使用应用程序清单进行信任工作,请考虑以下示例。 Microsoft创建面向 .NET Framework 3.5 的 ClickOnce 应用程序。 应用程序清单使用 <useManifestForTrust> 元素,并由Microsoft签名。 Adventure Works 使用自签名证书对部署清单进行签名。 Adventure Works 客户端配置为信任由 Microsoft 签名的任何应用。
当用户单击部署清单的链接时,ClickOnce 会在用户的计算机上安装该应用程序。 证书和部署信息在客户端计算机上唯一地标识 ClickOnce 的应用程序。 如果用户尝试从其他位置再次安装同一应用程序,ClickOnce 可以使用此标识来确定应用程序已存在于客户端上。
接下来,ClickOnce 检查用于对应用程序清单进行签名的 Authenticode 证书,该证书确定 ClickOnce 将授予的信任级别。 由于 Adventure Works 已将其客户端配置为信任Microsoft签名的任何应用程序,因此此 ClickOnce 应用程序将被授予完全信任。 有关详细信息,请参阅 受信任的应用程序部署概述。
为早期版本创建用户部署
如果开发人员正在将 ClickOnce 应用程序部署到使用旧版 .NET Framework 的客户,该怎么办? 以下部分总结了几个建议的解决方案,以及每个解决方案的优点和缺点。
代表客户对部署进行签名
一种可能的部署策略是让开发人员使用客户自己的私钥创建代表其客户对部署进行签名的机制。 这样,开发人员就无需管理私钥或多个部署包。 开发人员只是为每个客户提供相同的部署。 客户可以使用签名服务为其环境自定义它。
此方法的一个缺点是实现此方法所需的时间和费用。 虽然可以使用 .NET Framework SDK 中提供的工具生成此类服务,但它将为产品生命周期增加更多的开发时间。
如本主题前面所述,另一个缺点是,每个客户的应用程序的版本将具有相同的应用程序标识,这可能会导致冲突。 如果这是个问题,开发人员可以更改生成部署清单时使用的“名称”字段,以便为每个应用程序提供唯一的名称。 这将为每个版本的应用程序创建单独的标识,并消除任何潜在的标识冲突。 此字段对应于 -Name Mage.exe的参数,以及 MageUI.exe中“名称”选项卡上的“名称”字段。
例如,假设开发人员已创建名为 Application1 的应用程序。 开发人员可以基于此名称(例如 Application1-CustomerA、Application1-CustomerB 等)创建多个具有客户特定变体的部署,而不是使用“名称”字段设置为 Application1 的单个部署。
使用安装包进行部署
第二种可能的部署策略是生成Microsoft安装项目以执行 ClickOnce 应用程序的初始部署。 这可以采用多种不同的格式之一:作为 MSI 部署、可执行安装文件(.EXE),或者是与批处理脚本一起的 cab 文件(.cab)。
使用此方法,开发人员将提供一个部署,其中包括应用程序文件、应用程序清单和用作模板的部署清单。 客户将运行安装程序,这将提示他们输入部署 URL(用户从中安装 ClickOnce 应用程序的服务器或文件共享位置),以及数字证书。 安装程序应用程序还可以选择提示输入其他 ClickOnce 配置选项,例如更新检查间隔。 收集此信息后,安装程序将生成实际的部署清单,对其进行签名,并将 ClickOnce 应用程序发布到指定的服务器位置。
在这种情况下,客户可以通过三种方式对部署清单进行签名:
客户可以使用证书颁发机构(CA)颁发的有效证书。
作为此方法的变体,客户可以选择使用自签名证书对部署清单进行签名。 这样做的缺点是,当用户被询问是否安装它时,它将导致应用程序显示“未知发布者”一词。 但是,好处是,它可以防止较小的客户花费证书颁发机构颁发的证书所需的时间和资金。
最后,开发人员可以在安装包中包含自己的自签名证书。 这介绍了本主题前面讨论的应用程序标识的潜在问题。
设置部署项目方法的缺点是生成自定义部署应用程序所需的时间和费用。
让客户生成部署清单
第三种可能的部署策略是仅将应用程序文件和应用程序清单移交给客户。 在此方案中,客户负责使用 .NET Framework SDK 生成和签名部署清单。
此方法的缺点是,它要求客户安装 .NET Framework SDK 工具,并让熟练使用它们的开发人员或系统管理员。 某些客户可能要求一个解决方案,该解决方案需要很少或根本不需要技术工作。