如何正确设置IIS 7应用程序池标识?

10
在将我的网站部署到IIS7.5之后,我发现了一个奇怪的行为:当应用程序池标识默认保留为ApplicationPoolIdentity(根据 IIS应用程序池标识 的建议),Ninject似乎被忽略了,因为在创建第一个控制器时会出现以下错误:

System.InvalidOperationException: 尝试创建类型为“..MainController”的控制器时出错。请确保控制器具有无参数公共构造函数。 ---> System.DirectoryServices.DirectoryServicesCOMException: 发生操作错误。

我尝试授予IIS AppPool \<MySiteAppPool>对包含站点的文件夹(包括所有子文件夹和文件)的FullAccess,但这没有改变任何内容。
然而,当我将应用程序池标识设置为任何域帐户(甚至是简单的账户,没有管理员特权,也没有访问站点文件夹的任何权限), 它可以正常工作。
Ninject是通过NuGet软件包根据设置MVC3应用程序教程安装的。
我不确定这是否相关,该站点应该在具有Windows身份验证的域Intranet中工作。
因此,唯一的问题似乎与应用程序池标识有关。 尽管我很想使用推荐的方式,但我希望拥有ApplicationPoolIdentity,而不是域帐户。
这可能与什么相关? 是否可以将所有这些混合在一起?这里有一个类似问题的 SO 帖子:ASP.NET MVC 4 + Ninject MVC 3 = No parameterless constructor defined for this object,但那里也没有合适的答案。根据删除的评论建议,我尝试使用 NetworkService 作为标识并且它可以正常工作。然而,我猜这好像并不比非特权域帐户好多少。编辑后,我突然发现另一个依赖项:应用程序池标识在 SQL Server 上用于 Windows 身份验证,尽管我希望客户端用户的凭据在那里使用。同意通过模拟来访问远程 sql server 可以使用经过身份验证的凭据解决问题。但是 ApplicationPoolIdentity 和 Ninject 的问题仍然不清楚。文章提到的问题使我想到可能是由于虚拟帐户没有用户档案引起的。对我来说,这个方面仍然不清楚,因为你仍然可以使用 LoadUserProfile 属性启用 IIS 加载用户档案。如果虚拟帐户没有档案,IIS 要加载什么我就不明白了?据说:

 

IIS 不会加载 Windows 用户档案,但某些应用程序可能仍会利用它来存储临时数据。SQL Express 是这样一个应用程序的例子。但是,用户档案必须被创建才能将临时数据存储在档案目录或注册表中。NETWORKSERVICE 帐户的用户档案由系统创建并始终可用。然而,随着切换到唯一的应用程序池标识,系统不会创建用户档案。只有标准应用程序池(DefaultAppPool 和 Classic .NET AppPool)在磁盘上具有用户档案。如果使用自定义帐户,则不会创建用户档案。

管理员创建新的应用程序池。

但是,如果需要,可以通过将“LoadUserProfile”属性设置为“true”来配置IIS应用程序池以加载用户配置文件。


我在serverfault.com上找到了以下线程:

如何分配活动目录权限给默认的应用程序池标识

其中还说明了应用程序池标识无法作为网络服务工作,特别是无法查询AD。


你授予了完全访问权限给谁? - V4Vendetta
@V4Vendetta 我已将 FullAccess 授权给 IIS AppPool\<MySiteAppPool>,以便访问包含站点的文件夹(包括所有子目录和文件)。 - horgh
您可以将应用程序池设置为ApplicationPoolIdentity,然后使用asp模拟来使用特定用户登录到数据库。查看身份验证部分,您会发现关键是在web.config中的<identity impersonate="true" userName="" password="" />。 - TheKingDave
@TheKingDave 实际上我使用的是Windows身份验证。这两种身份验证方式可以同时应用吗? - horgh
我现在也遇到了同样的问题,无法解决它。你是如何解决的?可以分享一下吗! - yusuf.oguntola
显示剩余5条评论
2个回答

9

iispool\appPoolName 账户被称为虚拟账户,且是在Windows 2008中添加的。其本质并不是真正意义上的账户,而是允许使用基础账户的进程之间加强安全。

您计算机上的许多服务使用networkService,默认账户有网络访问权限。由于这个原因,如果攻击者利用其中一个服务,任何在同一账户下运行的其他进程都将是可访问的。而IIS等虚拟账户通过显示不同的账户名来防止这种情况发生,尽管它们仍然是相同的账户 - 您的ASP.NET应用程序仍然在以networkservice身份运行,并授予此账户对事物的访问权限。这也意味着,如果您需要访问网络资源,则iispool账户将像networkservice一样使用计算机域账户进行访问。

如果要访问远程SQL服务器,则应添加此帐户以允许从Web服务器访问。我建议您不要使用模拟用户,除非您真的非常需要知道SQL服务器上的用户是谁。如果不用它,您的应用程序安全性会更简单。

至于为什么您的注入不起作用,可能是您的任何依赖项失败了。例如,如果控制器A被注入了ClassB,而后者又被注入了ClassC,那么如果ClassC无法注入ClassD,整个链就会失败。我曾遇到过这种情况,并花费了一段时间才意识到它与我当时正在查看的东西有很大不同。


2
根据问题中的细节,听起来很像是一个权限问题导致抛出了COMException,从而阻止Ninject实例化MainController。这个异常与System.DirectoryServices有关,这些类用于查询Active Directory。
当IIS在正常的应用程序池账户下运行时,这些账户没有权限对Active Directory进行查询,可能会抛出COMException。我认为异常中的实际消息(找不到无参数构造函数)有点误导性,并且是Ninject尝试回退到另一个构造函数,因为正常的构造函数没有起作用。
这就解释了为什么当您将IIS应用程序池更改为以域帐户运行时,它突然起作用,因为该帐户确实有权限查询域。
从问题中并不清楚您是否自己使用System.DirectoryServices,或者Ninject/IIS/ASP是否在使用它们。如果您自己使用它们,请确保您的AD类中没有任何构造函数会引发异常(捕获并记录它们),这将防止应用程序在启动时崩溃。您可能会发现上面提到的权限问题。
如果您需要让IIS以普通应用程序池帐户的身份运行(这是一个好主意),但仍然作为域用户查询AD,则可以指定DirectoryEntry的凭据,并使用DirectorySearcher进行AD搜索。 如果您使用的是.Net 4或更高版本,则建议改用新的System.DirectoryServices.AccountManagement类(也允许您指定凭据)。
通过该方法,您将不需要任何模拟来进行AD查询,而您的应用程序池仍然可以以普通应用程序池帐户的身份运行。

这并不是严格的事实。网络服务是一个低特权帐户,可以访问网络资源。当它这样做时,它会使用机器域帐户。因此,如果您要访问AD,并且该计算机名为domain \ webserver,则将使用凭据domain \ webserver$。但这些凭证可能比您需要的权限少。 - Simon Halsey
1
@Simon,我更新了我的答案以澄清在AD查找中不需要模拟,并删除了对NetworkService帐户的引用。这可能会引起误解,因为IIS应用程序池帐户(例如ASP.Net v4.0)和NetworkService帐户之间有所不同,正如您所说的那样。 - Adam Rodger
@AdamRodger 我认为你指引了我正确的方向,因为我确实访问了AD,这可能是在虚拟账户下运行失败的原因。我会尽快检查一切。 - horgh
@AdamRodger,讨论同样的问题,我猜测:如何将Active Directory权限分配给默认应用程序池标识 - horgh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接