【问题标题】:External app config and encryption of settings外部应用配置和设置加密
【发布时间】:2016-10-06 21:11:41
【问题描述】:

我们有许多需要共享外部应用配置文件的应用和服务。外部文件包含一个 configSection,其中包含我们要加密的信息。 每个服务和应用程序都驻留在自己的应用程序文件夹中,这就是问题开始升级的地方。 在 App.config 中,可以使用“configSource”或“file”属性引用外部文件。无法使用“configSource”,因为外部配置文件不在应用文件夹或应用子文件夹中。因此我们必须使用“文件”属性。

<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();
}

因为我使用的是文件属性(我怀疑)。 config 部分在 App.config 中加密,而外部文件没有。在 App.config 中加密的只是

<customSettings file=”path to setting”/>

。这没什么用。

这意味着单个应用程序和服务无法加密外部配置文件。 然后我想到我将放置一个与外部配置文件位于同一目录中的小型应用程序。此应用程序的目的是通过使用“configSource”属性来加密外部配置文件。这种方法根本不起作用。什么都没有发生,也没有加密。

为了进一步调查,我在 App.config 中放置了“customSettings”并成功加密了该部分。然后我将加密数据复制到外部文件中,以测试加密是否可以在外部配置文件中工作。这适用于“configSource”,但在使用“file”属性时会引发异常。

抛出异常:

Unrecognized attribute 'configProtectionProvider'

由于我们必须在 app.config 中使用“文件”属性,我现在遇到了 2 个问题。

  1. 无法加密外部文件。
  2. 如果外部文件是手动加密的,我无法使用“文件”属性读取它。

【问题讨论】:

  • 我已经解决了我遇到的第一个问题。原来我需要调用:section.SectionInformation.ForceSave = true; 在实际保存配置之前。使用 configSource 属性时,外部配置文件现在被加密

标签: c# configurationmanager


【解决方案1】:

您可以选择创建自定义配置部分,避免使用 appsettings 部分并依赖自定义配置部分。当然,您需要创建自己的处理程序来读取外部文件。此时您可以指向任何文件,整个文件可能会被混淆并且不符合 XML 标准

或者您可以在应用程序设置中添加指向加密文件的设置并手动读取文件

【讨论】:

  • 感谢您提出的好观点。确实创建了我自己的处理程序。但这样做与NameValueFileSectionHandler 的做法是一致的。因此,与 .NET System.Configuration 命名空间中已有的内容具有尽可能多的协同作用。参考我上面的解决方案。
【解决方案2】:

经过大量研究并查看 NameValueFileSectionHandler 的代码后,我意识到如果外部 configSection 已加密,则该类无法解析 file="file path" 属性指向的 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 文件中定义的自定义提供程序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-30
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2011-12-24
    • 2011-06-23
    相关资源
    最近更新 更多