使用加密来保护密码
作者:Saad Ladki
介绍
本文档概述了为 IIS 7.0 及更高版本的服务器设置应用程序池和工作进程隔离所需的步骤。 应用程序池隔离需要保护 WAS(IIS 本地系统进程)需要访问的数据。 此数据的一个例子是应用程序池密码。 另一方面,工作进程隔离需要保护应用程序池标识需要访问的数据。 此数据的一个例子是匿名用户帐户密码。
先决条件
为了帮助简化此过程,提供了两段示例代码,它们会:
- 在 machine.config 中创建新的 RSA 加密提供程序。
- 在 machine.config 中设置默认提供程序的名称。
最后的先决条件部分将指导你设置四个将在后续主题中使用的用户帐户。
创建新的 RSA 加密提供程序应用程序
打开 Windows 记事本,在你任选的目录中创建一个名为 createProvider.cs 的文件,其中包含以下 C# 代码:
using System; using Microsoft.Web.Administration; using System.Configuration; namespace testingEncryption { public class createProvider { public static void Main(string[] args) { String keyContainerName = args[0]; String description = args[1]; String providerName = args[2]; System.Configuration.Configuration machineConfig = System.Configuration.ConfigurationManager.OpenMachineConfiguration(); System.Configuration.ProviderSettings settings = new System.Configuration.ProviderSettings(providerName, "System.Configuration.RsaProtectedConfigurationProvider, System.Configuration, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); settings.Parameters["description"] = description; settings.Parameters["keyContainerName"] = keyContainerName; settings.Parameters["cspProviderName"] = String.Empty; settings.Parameters["useMachineContainer"] = "true"; settings.Parameters["useOAEP"] = "false"; settings.Parameters["name"] = providerName; ProtectedConfigurationSection pcSection = (System.Configuration.ProtectedConfigurationSection)machineConfig.GetSection ("configProtectedData"); pcSection.Providers.Add(settings); machineConfig.Save(); } } }
接下来,启动提升的命令提示符:
- 单击“开始”菜单。
- 右键单击“命令提示符”。
- 选择“以管理员身份运行”。
在命令提示符窗口中,导航到保存 createProvider.cs 文件的位置,然后运行以下命令来编译代码:
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\csc.exe /reference:%SystemRoot%\System32\inetsrv\Microsoft.Web.Administration.dll createProvider.cs
此步骤现已完成。
创建应用程序以更改默认提供程序
打开 Windows 记事本,在你任选的目录中创建一个名为 setProvider.cs 的文件,其中包含以下 C# 代码:
using System; using Microsoft.Web.Administration; using System.Configuration; namespace testingEncryption { public class setProvider { public static void Main(string[] args) { String provider = args[0]; // example: DataProtectionConfigurationProvider System.Configuration.Configuration machineConfig = System.Configuration.ConfigurationManager.OpenMachineConfiguration(); ProtectedConfigurationSection pcSection = (System.Configuration.ProtectedConfigurationSection)machineConfig.GetSection("configProtectedData"); string oldEncryptionProviderName = pcSection.DefaultProvider; Console.WriteLine("The default provider is currently: " + oldEncryptionProviderName); Console.WriteLine("Changing the default provider to: " + provider); pcSection.DefaultProvider = provider; machineConfig.Save(); } } }
接下来,启动提升的命令提示符:
- 单击“开始”菜单。
- 右键单击“命令提示符”。
- 选择“以管理员身份运行”。
在命令提示符窗口中,导航到保存 setProvider.cs 文件的位置,然后运行以下命令来编译代码:
%SystemRoot%\Microsoft.NET\Framework\v2.0.50727\csc.exe /reference:%SystemRoot%\System32\inetsrv\Microsoft.Web.Administration.dll setProvider.cs
此步骤现已完成。
创建用户帐户
在此步骤中,我们将创建四个新的用户帐户,对它们的使用将贯穿整个文档。
若要开始,请按照以下步骤打开一个在管理权限下运行的命令 shell 窗口:
- 单击“开始”菜单。
- 右键单击“命令提示符”。
- 选择“以管理员身份运行”。
- 在命令窗口中执行以下命令:
net user /add AppPoolIdentity1 password1
net user /add AppPoolIdentity2 password2
net user /add AnonymousAccount1 password3
net user /add AnonymousAccount2 password
此步骤现已完成。
应用程序池隔离
IIS 有一个名为 WAS 的进程,该进程在 LOCALSYSTEM 的上下文中运行,并且是唯一需要访问应用程序池密码的进程。 在此任务中,我们将:
- 创建一个新的 RSA 密钥 (iisWasKey),只有 LOCALSYSTEM 和管理员有权访问它。 此密钥将用于加密每个应用程序池的密码。
- 创建两个应用程序池。
- 将这些应用程序池中的每一个配置为在不同的标识下运行,并使用 iisWasKey 加密它们的密码。
- 限制密钥文件的 NTFS 文件系统权限,使得只有 SYSTEM 和管理员才有权访问。
创建新的 RSA 密钥
- 单击“开始”菜单。
- 右键单击“命令提示符”。
- 选择“以管理员身份运行”。
- 在命令窗口中,导航到保存 createProvider.exe 的位置并运行以下命令:
createProvider.exe iisWasKey RsaKeyForWAS Rsa_WAS
验证是否正确发生了这些更改。 使用 Windows 记事本打开 %SystemRoot%\Microsoft.NET\Framework\v2.0.50727\config\machine.config
并验证新提供程序是否存在该部分的行:
keyContainerName="NetFrameworkConfigurationKey" cspProviderName=""
useMachineContainer="true" useOAEP="false" name="RsaProtectedConfigurationProvider"
type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
useMachineProtection="true" keyEntropy="" name="DataProtectionConfigurationProvider"
type="System.Configuration.DpapiProtectedConfigurationProvider,System.Configuration,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
cspProviderName="" useMachineContainer="true" useOAEP="false"
name="Rsa_WAS"
type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
加密应用程序池密码
默认情况下,每当属性被加密时,IIS 都会使用 defaultProvider 进行 machine.config 中定义的加密。它的默认值为 RsaProtectedConfigurationProvider。
在此步骤中,我们使用前面创建的 setProvider.exe 应用程序将提供程序更改为 iisWasKey,然后使用 IIS 管理器更改密码:
- 单击“开始”菜单。
- 右键单击“命令提示符”。
- 选择“以管理员身份运行”。
- 在命令窗口中,导航到保存 setProvider.exe 的位置并运行以下命令:
setProvider.exe Rsa_WAS
已成功更改默认提供程序 Rsa_WAS。
新建应用程序池
在此步骤中,我们将创建两个新的应用程序池,让这些池彼此隔离。 为此,请启动 IIS 管理器:
单击“开始”,键入“INetMgr.exe”,然后按 Enter(如果出现提示,请选择“继续”来提升权限)。
在“连接”部分中单击计算机名称旁边的 + 按钮。
单击“应用程序池”。
选择右侧标题为“添加应用程序池”的任务。
输入名称“AppPool1”,然后按“确定”,如下所示:
重复前面的步骤,但这次使用名称“AppPool2”。
请注意,AppPool1 和 AppPool2 的标识都是 NetworkService。 我们将通过右键单击“AppPool1”并选择“高级设置”来将其更改为我们之前创建的帐户
在标题“进程模型”下:
现在,标识值应如下所示:
单击“确定”以保存你的更改。
对“AppPool2”重复上一步,并使用用户名“AppPoolIdentity2”和密码“password2”。
你会看到 IIS 管理器中显示以下内容(主要是应用程序池的标识已更改):
使用 Windows 记事本并打开
%SystemRoot%\System32\Inetsrv\applicationHost.config
文件来验证更改。 导航到“applicationPools”部分,可以看到我们按预期使用 Rsa_WAS 密钥加密了应用程序池密码:password="[enc:Rsa_WAS:jAAAAAECAAADZgAAAKQAAAUkBfhWFbUHIt/qtlo+P7CiZC10r9H0DGBvAl U2mhiOxMoHXX6Dz0S8TQjKx2YTKvuE8y+SBUWrEs3JYzXKOkY45Q9z6E/3BFvru5oR9uzbjInASKF/83N N1tIEsoorQWmUOjnL4XM9RNzpqkY6TgyC3CyPUGN9fR7li5+AUupHHfgVPMzcLHfCsoq+ri+X6IbEnJdu cUEAYBn1P9F/Zxk=:enc]" /> password="[enc:Rsa_WAS:jAAAAAECAAADZgAAAKQAAEbQEa/sAmyLbryAR0hD3voip2+0RfzM44sXPekp I2H7HYLzta55NfLcG8vSPHhasahKVgO4wcIcT03CLSn+5koWvAaIRdeClhXWK/X8ZQPFooOpyhOqT0TEP5v jB+DXAKgq0RC6ufHFtrHMy0U69ew7/49YXEcrkF+o8OJZ1K+EkgA3J2ikHKxW0pFBU0tFvLCjt2/UXypfNI 0hYPe2syk=:enc]" />
锁定加密提供程序
默认情况下,IIS_IUSRS 在密钥创建时会被授予对密钥的读取访问权限。 但是,可以使用 ASPNET_REGIIS 工具来移除该访问权限。 要执行此操作,请在提升的命令提示符下运行以下命令:
cd /d %systemroot%
cd Microsoft.NET\Framework\v2.0.50727
aspnet_regiis.exe -pr iisWasKey IIS_IUSRS
这会移除 IIS_IUSRS(应用程序池标识组)对 iisWasKey 的读取访问权限,对它的访问应仅限于管理员和 LOCALSYSTEM。
工作进程隔离
本主题介绍如何通过创建两个属于不同应用程序池并具有不同匿名身份验证标识的新站点来设置工作进程隔离。 然后,为每个应用程序池创建新的 RSA 提供程序,以加密匿名密码。
创建新站点
在本部分中,我们将创建两个新站点,并将每个站点添加到我们之前创建的应用程序池。 若要开始,请按照以下步骤打开一个在管理权限下运行的命令 shell:
单击“开始”菜单。
右键单击“命令提示符”。
选择“以管理员身份运行”。
在命令窗口中,使用以下命令导航到你的 wwwroot 目录:
cd /d %SystemDrive%\inetpub\wwwroot
使用以下命令创建名为“one”的新目录和目录“two”:
mkdir one
mkdir two
在包含以下 HTML 代码的“one”和“two”目录中创建基本 Default.htm 文件:
<html><body>Hello from site X</body></html>
注意
根据文件的目录位置,将“X”替换为“one”或“two”。
现在,使用 IIS 管理器创建两个站点:
单击“开始”,键入“INetMgr.exe”,然后按 Enter(如果出现提示,请选择“继续”来提升权限)。
在“连接”部分中单击计算机名称旁边的 + 按钮。
右键单击“连接”下的树状视图中的“站点”,然后选择“添加网站”。
使用以下信息创建你的站点:
网站名称:One
应用程序池:AppPool1
物理路径:{你的 inetpub 目录的位置}\wwwroot\one
端口:81完成后,应如下所示:
单击“确定”以保存更改 。
重复前面的两个步骤,但这次对第二个站点使用以下信息:
网站名称:Two
应用程序池:AppPool2
物理路径:{你的 inetpub 目录的位置}\wwwroot\two
端口:82
你现已创建两个名为“One”和“Two”的新站点,并将它们添加到了“AppPool1”和“AppPool2”应用程序池。
用于测试你的站点的 URL 为:
http://localhost:81
(对于站点 One)http://localhost:82
(对于站点 Two)
为每个应用程序池创建新提供程序
在本部分中,我们将为每个应用程序池创建新的 RSA 提供程序:
单击开始菜单。
右键单击“命令提示符”。
选择“以管理员身份运行”。
在命令窗口执行中,导航到保存 createProvider.exe 的位置并运行以下命令:
createProvider.exe App1Key RsaKeyForAppPool1 Rsa_app1 createProvider.exe App2Key RsaKeyForAppPool2 Rsa_app2
为站点 One 设置匿名帐户
在你的提升的命令提示符窗口中,运行以下命令:
setProvider.exe Rsa_app1
返回 IIS 管理器,然后双击站点“One”。
双击“功能名称”标题下的“身份验证”项。
选择“匿名身份验证”,然后在右侧的“任务”标题下单击“编辑”,这会引出“编辑匿名身份验证凭据”对话框。
单击“特定用户”选项,然后单击“设置”按钮。
输入用户名“AnonymousAccount1”和密码“password3”,然后选择“确定”。
此时会显示以下对话框:
按下“确定”以保存你的更改。
为站点 Two 设置匿名帐户
在你的提升的命令提示符窗口中,运行以下命令:
setProvider.exe Rsa_app2
- 返回 IIS 管理器,然后双击站点“Two”。
- 双击“功能名称”标题下的“身份验证”项。
- 选择“匿名身份验证”,然后单击右侧的“任务”标题下的“编辑匿名凭据”对话框。
- 单击“特定用户”选项,然后单击“设置”。
- 输入用户名“AnonymousAccount2”和密码“password4”,然后选择“确定”。
- 单击“确定”以保存你的更改。
将加密提供程序重置为默认值
- 返回到你的提升的命令提示符窗口,并运行以下命令:
setProvider.exe RsaProtectedConfigurationProvider
注意
此更改可确保所有加密的未来属性都使用默认加密提供程序。
验证更改
验证我们想要的是否已发生。 使用 Windows 记事本打开 %SystemRoot%\System32\Inetsrv\applicationHost.config
文件:
请注意,AppPool1 和 AppPool2 的密码仍使用 Rsa_Was 密钥进行保护。
请注意,AnonymousAccount1 的密码也使用 Rsa_app1 密钥进行保护:
password="[enc:Rsa_app1:jAAAAAECAAADZgAAAKQAAKoz4LV7HyPQuyNzXh8gspB0rPG7j3Ijvn3d+jY3/f gma8ZxA7AHLUxjis9b0+Qu8XkLvsGn/A+F+m1O68gY1LkWzAcSW9ks81FuiBVhpZx73FzEo6aOz2QqBduJ7Xhu x923KMBqmwkIVJ0mVAdzwFIm6LWymwRXxNxDE4eosKsw6QP6Rd6duC8gckaLxrTndclErQYgGdMt3W6ofxzRMlc=:enc]" />
最后请注意,AnonymousAccount2 密码也使用 Rsa_app2 密钥进行保护:
password="[enc:Rsa_app2:jAAAAAECAAADZgAAAKQAAKmHMhCTICEUhGncSGCxQc6ll/QGXo0asEIzOf3rIjl sBDGRYhlDQWlf2QbFcIsBGYt8dHo9hzAQN/f03BPSlaFynevpSx4xJOg2/B8ATgPmCg4vgxpY5huZbGxongs55c Rr20WFXsxzlUuw1xoUZI8c1+7gQPOtF0Rwh1g8NBmb5ML/R3jAIFcMtVhaj0OOIfAP7JCjdInwztBqK0XO7FM=:enc]" />
锁定加密提供程序
保护上面的密钥的文件权限,如之前所做的那样。 在提升的命令提示符下运行以下命令:
cd /d %systemroot%
cd Microsoft.NET\Framework\v2.0.50727
aspnet_regiis.exe -pr App1Key IIS_IUSRS
aspnet_regiis.exe -pa App1Key AppPoolIdentity1
aspnet_regiis.exe -pr App2Key IIS_IUSRS
aspnet_regiis.exe -pa App2Key AppPoolIdentity2
这些命令会移除 IIS_IUSRS 读取密钥的能力,并仅添加需要密钥访问权限的应用程序池标识。
测试你的站点
现在测试你的站点:
http://localhost:81
http://localhost:82
一切都应像以前一样继续正常工作。
总结
总结一下,我们执行了以下任务来保护应用程序池设置:
- 创建了两个应用程序池
- 创建了两个本地用户帐户,并将它们配置为应用程序池标识
- 我们创建了一个管理加密密钥,并使用它来保护所有应用程序池标识密码
- 我们使用 ASPNET_REGIIS 移除了 IIS_IUSRS(应用程序池标识组)访问密钥的能力
这些任务有效地确保只有管理员和 SYSTEM 帐户才能读取应用程序池的密码。 因此,如果应用程序池中的应用程序尝试检索它们的(或任何)应用程序池的密码,则尝试会失败。
为了隔离工作进程设置,我们:
- 创建了新的匿名标识帐户
- 我们为应用程序池创建了一个新的提供程序
- 我们使用应用程序池密钥加密了匿名身份验证密码
- 我们为 IIS_IUSRS 移除了对匿名身份验证提供程序的访问权限,并只将访问权限授予应用程序池标识
这有效地确保了应用程序池标识可以解密它所属的匿名密码,而其他任何人都不可以。