8

对于 IIS 托管的 ASP.NET MVC 4 网站,我想在运行时在代码中动态调整机器密钥。

机器密钥、加密和验证密钥以及要使用的算法都存储在数据库中。我不想从文件中读取值web.config,而是想在应用程序启动期间注入这些值并让系统使用这些值。

有什么方法可以实现这一点而无需进行任何更改web.config(仅更改内存配置)?

我已经尝试访问配置部分,但它被标记为只读并且也是密封的,所以我无法覆盖IsReadOnly(). 但是,setter对我来说,有一个指标表明可能有一种方法可以删除只读标志。

var configSection = (MachineKeySection)ConfigurationManager.GetSection("system.web/machineKey");
if (!configSection.IsReadOnly())
{
       configSection.ValidationKey = _platformInfo.MachineKey.ValidationKey;
       configSection.DecryptionKey = _platformInfo.MachineKey.EncryptionKey;
       ...
}

有没有办法做到这一点?我能看到的唯一选择是使用像 AppHarbor 这样的自定义方法,但是如果可能的话,我宁愿坚持使用内置方法。

如果有人问我为什么要这样做,原因是,这是针对在 webfarm 中运行的大量相同网站。因此,必须拥有非自动生成的密钥(必须在每台服务器上相同)。此外,每个网站都应该被隔离,并且不应该共享相同的密钥。由于所有网站在物理表示上都是相同的,因此它们共享相同的物理位置。这就是 web.config 文件不能包含应用程序特定设置的原因。

编辑:如果根本不可能,至少确认一下会很有帮助。如前所述,可以使用自定义身份验证和加密方法,这将完全避免使用机器密钥设置。谢谢。

4

3 回答 3

8

这很难看,但我能够使用反射从配置部分临时删除只读位,设置密钥,然后恢复它:

var getter = typeof(MachineKeySection).GetMethod("GetApplicationConfig", BindingFlags.Static | BindingFlags.NonPublic);
var config = (MachineKeySection)getter.Invoke(null, Array.Empty<object>());

var readOnlyField = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
readOnlyField.SetValue(config, false);

config.DecryptionKey = myKeys.EncryptionKey;
config.ValidationKey = myKeys.ValidationKey;

readOnlyField.SetValue(config, true);
于 2017-03-13T13:17:05.037 回答
5

一旦 Web 应用程序启动,就无法以编程方式设置它。但是,仍然有可能实现您的目标。

如果每个应用程序都在自己的应用程序池中运行,并且每个应用程序池都有自己的标识,那么请检查applicationHost.config中的CLRConfigFile开关。您可以使用此每个应用程序池来注入新级别的配置。有关如何使用它的示例,请参阅http://weblogs.asp.net/owscott/archive/2011/12/01/setting-an-aspnet-config-file-per-application-pool.aspx 。您可以在每个应用程序池的自定义 CLR 配置文件中设置一个明确且唯一的 <system.web/machineKey> 元素。

这与 Azure 网站、GoDaddy 和其他需要基于每个应用程序设置默认显式机器密钥的主机使用的机制相同。请记住为将要访问它的应用程序池适当地 ACL 每个目标 .config 文件。

于 2013-08-28T03:29:13.360 回答
1

内部运行代码,可能不是。

但是,在另一个应用程序(如控制台)中,我使用以下代码解决了问题:

private static void ChangeWebConfig(string validationKey, string decryptionKey, string webConfigPath)
{
    ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
    configFileMap.ExeConfigFilename = webConfigPath;
    System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
    MachineKeySection section = (MachineKeySection)config.GetSection("system.web/machineKey");
    section.ValidationKey = validationKey;
    section.DecryptionKey = decryptionKey;
    config.Save();
}
于 2020-01-20T14:04:52.470 回答