在 Windows 应用程序中实现受保护的配置






4.70/5 (50投票s)
2006年8月29日
10分钟阅读

471110

5401
如何使用 ProtectedConfiguration API 来保护应用程序配置文件中的敏感信息。
引言
这一切都发生在我需要加密我的 Windows Forms 应用程序配置文件中的敏感信息时。我决定使用 Microsoft .NET 2.0 的新受保护配置功能来对其进行加密。
我开始在网上搜索,但无法找到任何适用于 Windows Forms 应用程序的受保护配置的实际应用。几乎所有的在线资源都告诉您可以使用 ASP.NET 来实现。在大多数文章中,加密是通过 aspnet_regiis 工具完成的,而 aspnet_regiis 不支持加密 Windows Forms 应用程序配置文件,因此几乎没有选择。
也许我说得不完全正确;网络上的一些资源确实提到您可以使用 System.Configuration.SectionInformation.ProtectSection
方法来加密 Windows Forms 应用程序配置文件。但没有一个给出实际桌面场景的示例。
当涉及到 ProtectSection
方法的实际实现时,存在以下问题:
ProtectSection
方法不像 apnet_regiis 那样是命令行工具,必须在运行时从应用程序的代码中调用它。使用此方法,可以加密应用程序配置文件中的特定配置节。所以,很可能在应用程序的Main
方法中使用类似下面的代码会奏效。Configuration config = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None); ConfigurationSection section = config.GetSection("connectionStrings"); if (!section.SectionInformation.IsProtected) { section.SectionInformation.ProtectSection( "MyUserDataProtectionConfigurationProvider"); } section.SectionInformation.ForceSave =true; config.Save(ConfigurationSaveMode.Modified);
这里,
System.Configuration.SectionInformation
的IsProtected
属性决定了配置节是否已加密。但是有一个问题,
Main
方法将在应用程序运行时调用。因此,所有敏感信息都将裸露在配置文件中,除非用户第一次运行应用程序。- 即使您通过创建一个独立的应用程序来加密配置节,该方法仍然存在两个问题:
- 内置的
ProtectedConfigurationProviders
,即RsaProtectedConfigurationProvider
和DpapiProtectedConfigurationProvider
,都不太适合这种情况,因为从一台机器上完成的加密不总能在另一台机器上解密。 - 这一个很有趣。实际加密的文件将是 Exe_Name.exe.config,而不是 app.config 本身。我们知道,默认情况下,每次构建项目时都会覆盖 Exe_Name.exe.config。
为了增加一点烦恼,在调试时,如果您启用了 Visual Studio 宿主进程(默认启用),您甚至不会注意到 Exe_Name.exe.config 文件的更改。如果是这样,Exe_Name.vshost.exe.config 将被加密。因此,所有这些都将使将加密的配置文件从生产环境移植到部署环境的过程变得困难。
- 内置的
正如您现在可能意识到的,受保护的配置并不是 Windows 应用程序的便捷选项。
由于 ProtectSection
方法是我们 Windows 应用程序配置文件唯一的出路,我们需要确定一种方法来使用 ProtectSection
方法,方法如下:
- 在应用程序首次运行之前
- 仅一次
- 在用户机器上
- 在正确的配置文件上
对于上述所有问题,有一个非常简单的解决方案。在安装程序类中使用 System.Configuration.SectionInformation.ProtectSection
方法。应用程序的 MSI 安装程序可以调用此安装程序类。因此,配置信息将在用户机器上安装时被加密。然后,.NET 会在运行时处理解密。
背景
对于不熟悉 .NET 2.0 新的受保护配置功能的人来说,它允许您加密应用程序配置信息,并配置应用程序在运行时自动解密它。这是通过使用不同的受保护配置提供程序实现的,这些提供程序可以在 App.config 文件中进行配置。每个提供程序都有自己的加密执行方法。有关详细信息,请参阅 MSDN 文章:使用受保护配置加密配置信息。
Using the Code
在两个内置的受保护配置提供程序,即 DpapiProtectedConfigurationProvider
和 RSAProtectedConfigurationProvider
中,我将使用 DpapiProtectedConfigurationProvider
,因为在我看来,它更适合 Windows 应用。它使用 Windows 内置的加密服务,并且可以配置为特定于计算机或特定于用户帐户的保护。
注意:本文的目的不是演示最佳的加密机制,而是演示如何在 Windows Forms 应用中使用受保护配置。
随时可以实现自己的提供程序,它可以使用自定义算法。有关更多详细信息,请参阅实现受保护配置提供程序。
重新创建演示项目
要重新创建演示项目,请按照以下步骤操作。
创建 Windows 应用程序项目
打开 Visual Studio 2005,并创建一个新的 C# Windows 应用程序项目。将其命名为 DemoWinApp。
打开“设置”文件,并添加一个名为 SecretMessage
的设置,如下所示:
打开 Form1
的设计器,并在上面添加一个 Label
控件,命名为 lblSecretMessage
,如下所示:
在 Form1
的 Load
方法中添加以下代码。
lblSecretMessage.Text = DemoWinApp.Properties.Settings.Default.SecretMessage;
指定受保护的配置提供程序
打开 App.Config 文件,并将以下代码添加为 Configuration
部分的子节点。
<configProtectedData>
<providers>
<add useMachineProtection="true" name="DPAPIProtection"
type="System.Configuration.DpapiProtectedConfigurationProvider,
System.Configuration, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</configProtectedData>
以上代码对于配置一个受保护的配置提供程序是必要的,该提供程序将用于加密和解密包含敏感信息的配置节。每当您想指定自己的提供程序及其自定义设置时,您可以使用 Configuration
部分下的 providers
元素的 add
元素声明一个新的提供程序实例,而 providers
元素又是 ConfigProtectedData
的子元素,而 ConfigProtectedData
又是 Configuration
部分的子元素。
DpapiProtectedConfigurationProvider
使用 Windows 内置的加密服务,并可以配置为特定于计算机或特定于用户帐户的保护。特定于计算机的保护对于匿名服务很有用,但安全性较低。特定于用户帐户的保护可以与以特定用户身份运行的服务一起使用。
注意上面列表中的属性 useMachineProtection=true
。这会将提供程序配置为使用特定于计算机的保护。因此,任何用户都可以成功地在该计算机上使用该应用程序。将其值设置为 false
会将提供程序配置为使用特定于用户帐户的保护。这里,使用应用程序意味着 .NET 运行时将无法解密之前加密的配置信息。因为,默认情况下,所有 Windows 应用程序都将在当前登录的用户帐户下运行,而我们计划在安装期间加密配置信息。因此,如果我们使用特定于用户帐户的保护,只有安装应用程序的用户才能使用该应用程序。
对于本文,我们将使用特定于计算机的保护。
属性 name="DPAPIProtection"
将用于在安装过程中加密配置节。
诸如 type
、Version
、Culture
和 PublicKeyToken
等其他属性标识了默认安装在全局程序集缓存中的 DpapiProtectedConfigurationProvider
程序集。
app.config 文件看起来是这样的:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section name="DemoWinApp.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<DemoWinApp.Properties.Settings>
<setting name="SecretMessage" serializeAs="String">
<value>This is the secret message.</value>
</setting>
</DemoWinApp.Properties.Settings>
</applicationSettings>
<configProtectedData>
<providers>
<add useMachineProtection="true" name="DPAPIProtection"
type="System.Configuration.DpapiProtectedConfigurationProvider,
System.Configuration, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</configProtectedData>
</configuration>
添加安装程序类
如前所述,我们将使用 System.Configuration.SectionInformation
类中的 ProtectSection
方法在安装程序类中,以便在安装时加密敏感配置信息。
在项目中添加一个新的安装程序类,并将其命名为 DemoWinAppInstaller.cs。
对于那些不熟悉使用安装程序的人来说,安装程序是帮助在计算机上安装应用程序的组件。自定义类派生自基类 Installer
,并且可以在自定义类中重写任何或所有 Install
、Commit
、Rollback
和 Uninstall
方法。在 Visual Studio 设置项目中,这些方法被配置为在安装过程的各个阶段调用。您可能已经猜到了,这些阶段是安装、提交、回滚和卸载。
这是自定义安装程序类的代码列表:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Configuration;
namespace DemoWinApp
{
[RunInstaller(true)]
public partial class DemoWinAppInstaller : Installer
{
public DemoWinAppInstaller()
{
InitializeComponent();
}
public override void Install(System.Collections.IDictionary stateSaver)
{
base.Install(stateSaver);
//get Configuration section
//name from custom action parameter
string sectionName = this.Context.Parameters["sectionName"];
//get Protected Configuration Provider
//name from custom action parameter
string provName = this.Context.Parameters["provName"];
// get the exe path from the default context parameters
string exeFilePath = this.Context.Parameters["assemblypath"];
//encrypt the configuration section
ProtectSection(sectionName, provName, exeFilePath);
}
private void ProtectSection(string sectionName,
string provName, string exeFilePath)
{
Configuration config =
ConfigurationManager.OpenExeConfiguration(exeFilePath);
ConfigurationSection section = config.GetSection(sectionName);
if (!section.SectionInformation.IsProtected)
{
//Protecting the specified section with the specified provider
section.SectionInformation.ProtectSection(provName);
}
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Modified);
}
}
}
请注意,在自定义安装程序中只重写了 Install
方法,其中包含加密 Configuration
部分的代码。Install
方法检索传递给安装程序的参数(不是 Install
方法本身),即 sectionName
(要加密的配置节)和 provName
(配置中定义的提供程序名称,将用于加密配置节)。我们稍后会看到如何将参数传递给安装程序。
同时请注意,您不必传递 assemblypath
参数;它默认存在于 Installer
的 Context
中。
然后 Install
方法调用一个私有方法 ProtectSection
来加密指定的配置节。此方法将使用实际的 System.Configuration.SectionInformation.ProtectSection
方法加密配置节,并将更改保存到配置文件中。
System.Configuration.ConfigurationManager
类的 OpenExeConfiguration
方法需要一个 EXE 路径作为参数,它会自动查找指定 EXE 的配置文件。
System.Configuration.SectionInformation
类的 ProtectSection
方法需要提供程序名称,该名称将用于加密配置节。
DemoWinApp 应用程序已完成。不要忘记构建项目。
创建 Visual Studio 设置项目
现在,让我们看看如何创建一个 Visual Studio 设置项目,该项目将利用上面介绍的安装程序类在安装时加密敏感配置信息。
向解决方案添加一个新的设置项目,并将其命名为 DemoWinAppSetup。
在文件系统编辑器中,将 DemoWinApp 项目的主输出添加到设置项目中。
使用安装程序类与 Visual Studio 设置项目进行集成的关键是自定义操作。
打开自定义操作编辑器,并将 DemoWinApp 项目的主输出添加到 Install 文件夹下。
打开新添加的自定义操作的属性窗口,并在 CustomActionData
属性中添加自定义操作参数及其值。
请注意指定参数的格式。每个参数的形式为 /[Parameter Name]="[Value]"。单个参数由空格分隔。确保参数名称、等号和参数值之间没有空格。
要加密整个 Settings
部分,sectionName
参数的值已设置为 applicationSettings/DemoWinApp.Properties.Settings
,这是 App.Config 文件中 Settings
节点的路径。
请注意,在 Settings.settings 文件中添加值会自动在 App.Config 中创建 Settings
节点,如下所示:
<applicationSettings>
<DemoWinApp.Properties.Settings>
<setting name="SecretMessage" serializeAs="String">
<value>This is the secret message.</value>
</setting>
</DemoWinApp.Properties.Settings>
</applicationSettings>
provName
是前面在 App.config 文件中指定的提供程序名称。
现在我们准备就绪。构建设置项目以生成 MSI 安装程序包。
运行应用程序
运行生成的安装程序包以安装应用程序。转到安装文件夹,并打开配置文件。注意 applicationSettings/DemoWinApp.Properties.Settings
部分。
在我的例子中,它看起来像这样:
<applicationSettings>
<DemoWinApp.Properties.Settings configProtectionProvider="DPAPIProtection">
<EncryptedData>
<CipherData>
<CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAJY9eXbg340Gn
Ay8Dyzkf4QQAAAACAAAAAAADZgAAqAAAABAAAAAac+j1
UbifDAtrOUt9xNUWAAAAAASAAACgAAAAEAAAAKwqPS6A
bcFdlDZiS8gBMvCIAQAAgBPMemCdMCcX6juvCaB02kNJ
Vb3tyHHLztYWkMyNgs60cIBiqQbNYPUcPkuMg42tbffk
0VQ0KEwMu8/mRAc4+LQwni9kRbpSR4GOUPoOzLSrdxcK
6D1mjntJ+804dZ7fk9gq793GpPJroV0VfxoaMBDZtHKw
uRbAnFvVn+yWfH6ZVN1gQFIM3vhinc/kpiBB+pPLCO/5
XbsOfwu3eLSw436LGqfTPsvAj6JY6pax8hd7KnIsCDte
EkZVGjHAfJnSj6mB5vI9u7fBLwjTa0V4qhznW+lcb6uP
JeR565sRnJq7Od+3c716bJ6fOS/AY91zF+f5rYLN+ebZ
ZnKabrilA6+xS70+rSPuLnXueKp6UymP0R4k9oVjfmAm
Utd4/PYuZqk+nKbEyJwr8lzc7lkwsy/aYE7IK9/BHlDf
rpJfR0B11ZeUBmXbGLD0N0hFQHZO6FHDxnRIzadJx7UX
o5VGVoE63tjAnDfRtj/UbudIq8GhM8CHxkh0o/AUuEpo
PsobGQ576EDdwo4UAAAAP2wB/QutHyUIYCG6T7n6YNbE
4gg=</CipherValue>
</CipherData>
</EncryptedData>
</DemoWinApp.Properties.Settings>
</applicationSettings>
因此,正如您所看到的,安装过程已经加密了 SecretMessage
设置,该设置是 applicationSettings/DemoWinApp.Properties.Settings
部分的子节点。
请注意,configProtectionProvider
属性已自动添加到 DemoWinApp.Properties.Settings
部分,这告诉 .NET 运行时该配置节已加密,以及使用哪个提供程序进行解密。
现在,解密配置节的责任在于 .NET 运行时,而不是应用程序开发人员。
回想一下,在 DemoWinApp 应用程序中,我们没有添加任何代码来在访问 SecretMessage
设置之前解密它。
lblSecretMessage.Text = DemoWinApp.Properties.Settings.Default.SecretMessage;
现在,运行安装在您 PC 上的 DemWinApp 应用程序。
输出应如下所示:
结论
ProtectedConfiguration
API 是保护应用程序配置文件中敏感信息的良好且干净的方式。不幸的是,内置的 ProtectedConfigurationProvider
并不非常适合许多 Windows 应用程序场景,例如,高级用户可以轻松开发自己的应用程序并为本文中使用的提供程序配置(特定于计算机的 DpapiProtectedConfigurationProvider
)解密配置信息。但对于许多场景,您仍然可以很好地将其与 Windows 应用程序一起使用。如前所述,本文的目的不是演示最佳的加密机制,而是演示如何在 Windows Forms 应用中使用受保护配置。如果您想更精确地控制实际的加密算法,您可以轻松创建自定义的 ProtectedConfigurationProvider
。有关更多详细信息,请参阅实现受保护配置提供程序。