我们有许多需要共享外部应用配置文件的应用和服务。外部文件包含一个configSection,其中包含要加密的信息。 每个服务和应用程序都驻留在自己的应用程序文件夹中,这就是问题开始升级的地方。 在App.config中,可以使用“configSource”或“file”属性引用外部文件。无法使用'configSource',因为外部配置文件不驻留在app文件夹或app子文件夹中。因此我们必须使用'file'属性。
<customSettings file=”path to setting”/>
'customSettings'的configSection定义如下:
<configSections>
<section name="customSettings" type="System.Configuration.NameValueFileSectionHandler, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</configSections>
然后我尝试使用以下代码加密configSection:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection section = config.GetSection("customSettings");
if (!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
config.Save();
}
因为我正在使用文件属性(我怀疑)。配置部分在App.config中加密,外部文件不加密。在App.config中加密的只是
<customSettings file=”path to setting”/>
。这很没用。
这意味着单个应用程序和服务无法加密外部配置文件。 然后我想到我会将一个小应用程序放在与外部配置文件相同的目录中。此应用程序的目的是使用“configSource”属性来加密外部配置文件。这种方法根本不起作用。没有任何事情发生,也没有加密。
为了进一步调查,我将'customSettings'放在App.config中并成功加密了该部分。然后,我将加密数据复制到外部文件,以测试加密是否可以在外部配置文件中工作。这适用于'configSource',但在使用'file'属性时抛出异常。
抛出异常:
Unrecognized attribute 'configProtectionProvider'
由于我们必须在app.config中使用'file'属性,现在我有2个问题。
答案 0 :(得分:1)
您可以选择创建自定义配置部分,避免使用appsettings部分并依赖自定义配置部分。您当然需要创建自己的处理程序来读取外部文件。您可以在此时指向任何文件,整个文件可能会被混淆并且不符合XML标准
或者您可以在应用设置中添加指向加密文件并手动读取文件的设置
答案 1 :(得分:0)
经过大量研究并查看NameValueFileSectionHandler
的代码后,我意识到该类无法解析file="file path"
属性指向的configSection,如果外部configSection所在加密。在NameValueFileSectionHandler
中不知道这是不是一个错误。也许有人可以回答这个问题。
但是我最终编写了自己的NameValueFileSectionHandler
,它可以返回NameValueCollection
并处理加密的外部配置文件。
public class NameValueFileProtectedSectionHandler : IConfigurationSectionHandler
{
public object Create(object parent, object configContext, XmlNode section)
{
object result = parent;
XmlNode fileAttribute = section.Attributes.RemoveNamedItem("file");
if (fileAttribute == null && fileAttribute.Value.Length == 0)
{
return new NameValueSectionHandler().Create(result, null, section);
}
IConfigErrorInfo configXmlNode = fileAttribute as IConfigErrorInfo;
if (configXmlNode == null)
{
return null;
}
string directory = Path.GetDirectoryName(configXmlNode.Filename);
string absoluteFilePath = Path.GetFullPath(directory + fileAttribute.Value);
if (!File.Exists(absoluteFilePath))
{
throw new ConfigurationErrorsException(string.Format("external config file: {0} does not exists", absoluteFilePath));
}
var configXmlDocument = new ConfigXmlDocument();
try
{
configXmlDocument.Load(absoluteFilePath);
}
catch (XmlException e)
{
throw new ConfigurationErrorsException(e.Message, e, absoluteFilePath, e.LineNumber);
}
if (section.Name != configXmlDocument.DocumentElement.Name)
{
throw new ConfigurationErrorsException(string.Format("Section name '{0}' in app.config does not match section name '{1}' in file '{2}'", section.Name, configXmlDocument.DocumentElement.Name, absoluteFilePath));
}
var nodeToDecrypt = configXmlDocument.DocumentElement["EncryptedData"];
if (nodeToDecrypt == null)
{
throw new ConfigurationErrorsException(string.Format("External encrypted file {0} does not contain EncryptedData element", absoluteFilePath));
}
var protectionProvider = new DpapiProtectedConfigurationProvider();
var decryptedConfigSection = protectionProvider.Decrypt(nodeToDecrypt);
result = new NameValueSectionHandler().Create(result, null, decryptedConfigSection);
return result;
}
}
处理程序仅限于默认配置加密。但我可以想象,可以扩展Create函数以支持app.config文件中定义的自定义提供程序。