65.9K
CodeProject 正在变化。 阅读更多。
Home

让您的 ASP.NET 访问您的资源

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.16/5 (12投票s)

2007 年 3 月 20 日

13分钟阅读

viewsIcon

225106

本教程展示了如何使用 NT AUTHORITY\Network Service 机器帐户来访问本地和网络资源。

引言

作为一名 Web 管理员,我习惯于在生产服务器上部署 Web 应用程序的更改。两天前,我花了比正常工作日多出 6 个小时的时间,我和我们的开发人员试图解决一个问题,当我们尝试在应用程序中部署一个允许在线用户在服务器上的特定文件夹中撰写文章和上传照片的新功能时,该问题出现了。

当我们尝试测试应用程序上传图像文件的功能时,问题就出现了这个错误。

"d:\visitorsUpload\Vu01.jpg" 的路径访问被拒绝。详细异常:System.UnauthorizedAccessException:"d:\visitorsUpload\Vu01.jpg" 的路径访问被拒绝。

我已确保该文件夹的所有权限都设置正确,ASPNET 帐户将具有读写权限,iuser_machinename 将具有读权限,该文件夹的虚拟目录将具有读权限。

(错误仍然显示)。

我们在网上尽可能地搜索解决方案,但没有找到任何可接受的!

在这种情况下,必须有一个帐户负责访问 ASP.NET 中的本地和网络资源。那个帐户是什么?它是如何工作的?我们如何了解更多关于它及其在访问 ASP.NET 资源方面的有用用途?

让我们一起去了解使用此帐户访问资源所施加的限制。

使用此帐户访问以下类型的资源

  • 本地文件系统
  • Windows 事件日志
  • Windows 注册表
  • 本地和远程数据库

关于网络服务帐户

网络服务帐户是服务控制管理器 (SCM) 使用的一个本地帐户。此帐户未被安全子系统识别,因此您无法在调用 LookupAccountName 函数时指定其名称。它在本地计算机上拥有最低权限,并在网络上作为计算机运行。该帐户在所有区域设置中的名称均为 NT AUTHORITY\NETWORK SERVICE。此帐户没有密码。如果在调用 CreateService 函数时指定 NetworkService 帐户,则提供的任何密码信息都将被忽略。

以网络服务帐户上下文运行的服务会向远程服务器呈现计算机的凭据。默认情况下,远程令牌包含 Everyone 和 Authenticated Users 组的安全标识符 (SID)。

默认情况下,Windows Server 2003 上的 Microsoft Internet Information Services (IIS) 6.0 在使用 NT AUTHORITY\Network Service 帐户标识的应用程序池中运行 ASP.NET 应用程序。该帐户是具有有限权限的最低特权机器帐户。使用此帐户运行的应用程序对事件日志、注册表和文件系统的访问受到限制。该帐户确实拥有网络凭据,这意味着您可以使用它通过 Windows 身份验证来访问网络资源和远程数据库。网络资源必须与您的 Web 服务器位于同一域或受信任的域中。

在某些情况下,使用自定义域服务帐户比使用网络服务帐户更好。如果您想这样做,则应使用自定义域服务帐户:

  • 您想将单个服务器上的多个应用程序彼此隔离。
  • 您需要为每个应用程序在本地和远程资源上拥有不同的访问控制。例如,如果访问权限仅限于您的应用程序帐户,则其他应用程序无法访问您的应用程序数据库。
  • 您想使用 Windows 审核来单独跟踪每个应用程序的活动。
  • 您想防止对通用网络服务帐户的访问控制或权限进行的任何意外或故意更改影响您的应用程序。

以下是如何展示您如何使用网络服务帐户访问各种类型的资源,包括事件日志、注册表、文件系统和数据库。

文件访问

默认情况下,网络服务帐户对 IIS 服务器的根文件夹具有读取和执行权限。IIS 服务器的根文件夹名为 Wwwroot。这意味着部署在根文件夹内的 ASP.NET 应用程序已经对其应用程序文件夹具有读取和执行权限。但是,如果您的 ASP.NET 应用程序需要使用其他位置的文件或文件夹,则必须专门启用访问。

授予网络服务文件访问权限

要为以网络服务身份运行的 ASP.NET 应用程序提供访问权限,您必须授予网络服务帐户访问权限。

要为特定文件或文件夹授予读取、写入和修改权限

1. 在 Windows 资源管理器中,找到并选择所需的文件。

2. 右键单击文件,然后单击“**属性**”。

3. 在“**属性**”对话框中,单击“**安全**”选项卡。

4. 在“**安全**”选项卡中,检查用户列表。如果未列出网络服务帐户,请添加它。

5. 在“**属性**”对话框中,单击“**网络服务**”用户名,然后在“** NETWORK SERVICE 的权限**”部分,选择“**读取**”、“**写入**”和“**修改**”权限。

6. 单击“**应用**”,然后单击“**确定**”。

您的 ASP.NET 应用程序现在可以写入指定的文件。

**注意**:如果需要为运行 ASP.NET 应用程序的所有帐户(网络服务或自定义服务帐户)授予对文件资源的同等访问权限,则可以授予对 **IIS_WPG** 组的访问权限,而不是专门授予网络服务帐户。用于运行 ASP.NET 的任何帐户都必须是 **IIS_WPG** 组的成员。

**安全提示:**您可以使用 NTFS 特殊权限来限制对此帐户的访问。

1. 在 Windows 资源管理器中,找到并选择所需的文件夹。

2. 右键单击文件夹,然后单击“**属性**”。

3. 在“**属性**”对话框中,单击“**安全**”选项卡。

4. 单击“高级”按钮。

5. 从权限条目中选择“网络服务”帐户,然后单击“编辑”按钮,这将打开您文件夹的特殊权限条目。

6. 拒绝 **(删除子文件夹和文件、删除)**,取消选中 **(完全控制、遍历文件夹/执行文件、读取权限、更改权限、获取所有权)**。

7. 单击“**应用**”,然后单击“**确定**”。

您的 ASP.NET 应用程序现在可以写入指定的文件夹,但权限最严格。

事件日志访问

使用网络服务标识运行的应用程序可以通过现有的事件源写入事件日志,但由于注册表权限不足,它们无法创建新的事件源。当您使用 **EventLog.Write** 方法时,如果指定的事件源不存在,该方法将尝试创建事件源并生成安全异常。

**注意** 使用应用程序特定的事件源很有用,这样您的应用程序的事件就可以轻松地区分于其他应用程序的事件。**

要使您的 ASP.NET 应用程序能够使用尚不存在的事件源写入事件日志,您有两个选择:

· 在应用程序安装时创建新的事件源。

· 手动在注册表中创建新的事件源条目。

在安装时创建新的事件源

通过此选项,您可以创建一个专门的安装程序类,并使用安装实用程序运行它,以便在具有管理员权限的安装时创建新的事件源。您可以使用管理员帐户运行安装实用程序,以便它有权创建新的事件源。

创建安装程序类以创建事件源

1. 使用 Visual Studio .NET 2005 创建一个名为 InstallerClass.dll 的类库项目。为 InstallerClass 项目添加对 System.Configuration.Install 的引用。

2. 将类命名为 **CustomEventLogInstaller**,并使其继承自 **System.Configuration.Install.Installer**。

3. 将类的 **RunInstaller** 属性设置为 **true**。

4. 为应用程序需要的每个新事件日志创建一个 **System.Diagnostics.EventLogInstaller** 实例,并调用 **Installers.Add** 将实例添加到您的项目安装程序类中。以下示例类将一个名为 customLog 的新事件源添加到应用程序事件日志中。

using System;
using System.Configuration.Install;
using System.Diagnostics;
using System.ComponentModel;

[RunInstaller(true)]
public class CustomEventLogInstaller: Installer
{
private EventLogInstaller customEventLogInstaller;
public CustomEventLogInstaller()
{
// 创建 'EventLogInstaller' 的实例。
customEventLogInstaller = new EventLogInstaller();
// 设置要创建的事件日志的“源”。
customEventLogInstaller.Source = "customLog";
// 设置要从中创建源的“事件日志”。
customEventLogInstaller.Log = "Application";
// 将 myEventLogInstaller 添加到“InstallerCollection”。
Installers.Add(customEventLogInstaller);
}
public static void Main()
{
}
}

5. 编译 InstallerClass.dll 库的代码。

6. 使用具有管理员权限的帐户运行 InstallUtil.exe 实用程序,并在命令行中提供 DLL 的名称。例如,打开 Visual Studio 命令提示符并输入以下命令。

InstallUtil.exe <dll path>\InstallerClass.dll

当使用安装程序类调用安装实用程序时,它会检查 **RunInstallerAttribute**。如果为 **true**,则实用程序将安装 **Installers** 集合中的所有项。这将为您的 ASP.NET 应用程序创建指定的事件源。

手动创建新的事件源条目在注册表中

如果您无法在安装时创建事件源,并且您处于部署阶段,管理员应该在以下注册表项下手动创建一个新的事件源条目:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\<LogName>

要在此注册表项下手动创建新的事件源条目:

1. 启动注册表编辑器工具 Regedit.exe。

2. 使用应用程序事件日志,展开左侧面板中的大纲列表以找到以下注册表子项:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application

3. 右键单击“**Application**”子项,指向“**新建**”,然后单击“**项**”。

4. 输入新事件源作为项名称,然后按 **Enter**。

网络服务帐户可以使用新的事件源来写入事件。

**注意** 您不应授予 ASP.NET 进程帐户(或您的应用程序使用模拟时的任何模拟帐户)对 **HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\** 注册表项的写入权限。如果您允许对该项的写入访问,并且该帐户被泄露,攻击者就可以修改系统上任何日志的所有与日志相关的设置,包括日志的访问控制。

运行状况监视

ASP.NET 2.0 版运行状况监视会在配置时写入 Windows 应用程序事件日志以报告重要的生命周期和安全事件。您可以通过 ASP.NET 运行状况监视在代码中引发自定义事件以写入事件日志。此方法不使用 **EventLog.WriteEntry**,但您仅限于使用预定义的事件源。

注册表访问

网络服务帐户没有写入注册表的权限。如果您的应用程序需要写入注册表,您必须在所需的注册表项上配置必要的访问控制列表 (ACL)。

授予网络服务注册表访问权限

在以下示例中,应用程序需要更改和显示 Windows 自动同步的 Internet 时间服务器的名称。操作员可以通过“控制面板”的“日期和时间”项中的“Internet 时间”选项卡来更改此设置。

您的应用程序需要修改以下注册表项:**
HKLM\SOFTWARE\ Microsoft\Windows\CurrentVersion\DateTime\Servers**

要允许网络服务帐户对上述注册表项拥有写入访问权限:

您需要使用具有修改注册表安全权限的管理员帐户执行以下步骤:

1. 在任务栏上,单击“**开始**”,然后单击“**运行**”。在“**打开**”框中键入 **regedit**,然后单击“**确定**”。

2. 展开左侧面板中的大纲列表,以在上述注册表路径中找到 DateTime 文件夹图标。

3. 右键单击 DateTime 文件夹,然后单击“**权限**”。

4. 在“**Servers 的权限**”对话框中,单击“**添加**”按钮。

5. 在“**选择用户、计算机或组**”对话框中,在文本框中键入 **NETWORK SERVICE**,然后单击“**检查名称**”。网络服务名称将带下划线;这表示它是一个有效的安全主体。单击“**确定**”。

6. 在“**Servers 的权限**”对话框中,从列表中单击“**网络服务**”用户名,然后在“**NETWORK SERVICE 的权限**”部分,单击“**高级**”。

7. 在“Servers 的高级安全设置”对话框中,单击“网络服务”,然后单击“编辑”。

8. 在“**Servers 的权限条目**”对话框中,在“**允许**”列中选中“**设置值**”和“**创建子项**”复选框以允许写入访问。单击“**确定**”几次,直到“**权限**”对话框关闭。

**注意** 您在编辑注册表时应小心,因为任何错误都可能导致系统不稳定。

您的 ASP.NET 应用程序现在可以使用类似以下示例的代码来更改和显示 Internet 时间服务器的名称。

using Microsoft.Win32;
...
protected void Button1_Click(object sender, EventArgs e)
{
//更改时间服务器
RegistryKey rk = Registry.LocalMachine.OpenSubKey(
@"SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers",
true); //可写 - 此操作将因权限不足而失败
string sDefault = (String)rk.GetValue("");
int iDefault = Convert.ToInt32(sDefault);
//这是所有服务器名称的数组
string[] sServers = rk.GetValueNames(); //需要枚举子项
iDefault++;
if (iDefault >= sServers.Length)
iDefault=1;
rk.SetValue("", iDefault.ToString());
//更新显示
Response.write(rk.GetValue(sServers[iDefault]).ToString());
}

SQL Server

ASP.NET 应用程序在连接数据库时应使用 Windows 身份验证。通过使用 Windows 身份验证,您可以避免在连接字符串中存储数据库凭据,并避免将密码通过网络传递到数据库服务器。

使用 Windows 身份验证时,默认情况下会使用您应用程序的进程帐户进行身份验证。要能够访问数据库,您的帐户需要:

· 数据库服务器上的 SQL Server 登录。

· 在所需数据库中访问所需对象(例如,存储过程、视图或表)的权限。

授予对本地 SQL Server 的访问权限

当 SQL Server 位于 Web 服务器上时,您必须为 NT AUTHORITY\Network Service 帐户创建一个数据库登录。

要使用网络服务访问本地 SQL Server 数据库:

1. 启动 SQL Server 企业管理器。

2. 展开左侧面板中的文件夹,并找到本地 SQL Server 的“**安全性**”文件夹。

3. 右键单击“**安全性**”文件夹中的“**登录名**”,然后单击“**新建登录名**”。

4. 在“**SQL Server 登录属性 - 新建登录名**”对话框中,在“**名称**”框中输入 **NT AUTHORITY\NETWORK SERVICE**。接受其他设置的默认值,然后单击“**确定**”。

5. 展开“数据库”文件夹,然后展开“Pubs”(或等效)数据库。

6. 右键单击“**用户**”,然后单击“**新建数据库用户**”。

7. 在“**数据库用户属性 - 新建用户**”对话框中,选择 NT AUTHORITY\NETWORK SERVICE 帐户。

8. 在“**数据库中的允许角色**”列表中,选中“**db_datareader**”复选框。

9. 单击“**确定**”,然后关闭 SQL Server 企业管理器。

现在,网络服务帐户有权读取指定数据库表中数据的权限。

实际上,您的应用程序的需求可能更复杂。例如,您可能希望允许对某些表进行读取访问,并允许对其他表进行更新访问。为减轻 SQL 注入风险而推荐的方法是授予网络服务帐户对选定存储过程的执行权限,并且不提供直接的表访问。

授予对远程 SQL Server 的访问权限

如果您正在访问同一域(或受信任域)中另一台服务器上的数据库,则网络服务帐户的网络凭据将用于向数据库进行身份验证。网络服务帐户的凭据形式为 **DomainName\AspNetServer$**,其中 **DomainName** 是 ASP.NET 服务器所在的域,**AspNetServer** 是您的 Web 服务器名称。

例如,如果您的 ASP.NET 应用程序运行在名为 SVR1 的服务器上,该服务器位于 CONTOSO 域中,则 SQL Server 会看到来自 CONTOSO\SVR1$ 的数据库访问请求。

要使用网络服务访问远程 SQL Server:

要授予对同一域或受信任域中的远程数据库服务器的访问权限,请按照前面针对本地数据库的步骤进行操作,但请在第 4 步中,使用 **DomainName\AspNetServer$** 帐户创建数据库登录。

**注意** 在生产环境中,您应该将网络服务帐户放入 Windows 组中,并为该 Windows 组创建 SQL Server 登录。

参考

http://msdn2.microsoft.com/en-us/library/ms998320.aspx

http://dotnetqpearl.net/blogs/default.aspx

A.Kader

© . All rights reserved.