写入事件日志时出现System.Security.SecurityException异常

200

我正在尝试将一个ASP.NET应用程序从Server 2003(和IIS6)迁移到Server 2008(IIS7)。

当我尝试在浏览器上访问该页面时,会出现以下错误:

“/”中的服务器错误应用程序。

安全性异常

描述:应用程序尝试执行安全策略不允许的操作。若要授予此应用程序所需的权限,请联系系统管理员或更改配置文件中的应用程序信任级别。

异常详细信息: System.Security.SecurityException:未找到来源,但无法搜索某些或所有事件日志。不可访问的日志:Security

源错误:

当前 Web 请求的执行期间生成了一个未经处理的异常。可以使用下面的异常堆栈跟踪标识异常的起源和位置。

堆栈跟踪:

[SecurityException: 未找到来源,但无法搜索某些或所有事件日志。不可访问的日志:Security。]

System.Diagnostics.EventLog.FindSourceRegistration(String source, String machineName, Boolean readOnly) +562 System.Diagnostics.EventLog.SourceExists(String source, String machineName) +251

[snip]

我所做的解决方法如下:

  1. 给“Everyone”在注册表键 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Security 上赋予完全访问权限。这有效果,但在生产中无法这样操作。因此,我在运行应用程序几分钟后删除了“Everyone”的许可,并出现了错误。

  2. 我使用提升的权限在应用程序日志和安全日志中创建了来源(并通过regedit验证了其存在),但错误仍然存在。

  3. 我在web.config文件中(以及使用appcmd.exe)将应用程序设置为完全信任级别,但没有效果。

有没有人对这里可以做些什么有想法?

PS:这是对该问题的跟进。我按照给出的答案尝试了,但无济于事(请参见上述#2)。


当我尝试在以NetworkService身份运行的.Net服务中写入自定义源时,出现了这个问题。我只是将事件日志源更改为与通过.Net服务安装程序设置的服务名称匹配,而无需设置注册表权限,它就可以正常工作了。我注意到这一点是因为在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application中已经有了服务名称作为键。 - Jon Adams
1
相关资料:https://dev59.com/MnVC5IYBdhLWcg3wdw65#7848414 - Chris S
2
另一个可能的答案:右键单击exe文件,选择“以管理员身份运行”。 - Entree
你需要在代码中暂时禁用模拟身份,更多详情请查看此链接:**源未找到,但某些或所有事件日志无法搜索。无法访问的日志:安全。** - Mohamed
这个错误可能是由于尚未创建的自定义事件源导致的。请注意,错误没有提到找不到哪个源。首先尝试创建您的源日志,因为这种误导性的错误并不总是由于安全日志或缺少足够权限而引起的。另请参见https://dev59.com/W1DTa4cB1Zd3GeqPHDK2#3622535。 - Suncat2000
23个回答

174
给予“网络服务”对“EventLog/Security”键的读取权限(如Firenzi和royrules22所建议的),请按照链接中的说明进行操作。
1. 打开注册表编辑器: 选择“开始”,然后选择“运行”。输入“regedt32”或“regedit”。
2. 导航/展开到以下键:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Security
3. 右键单击此条目,然后选择“权限”。
4. 添加“网络服务”用户。
5. 给予它读取权限。 更新:上述步骤适用于开发人员机器,在这些机器上,您不需要使用部署过程来安装应用程序。
然而,如果您将应用程序部署到其他机器上,请考虑根据SailAvidNicole Calinoiu的建议,在安装过程中注册事件日志源

我正在使用PowerShell函数(在Octopus Deploy.ps1中调用)。

function Create-EventSources() {
    $eventSources = @("MySource1","MySource2" )
    foreach ($source in $eventSources) {
            if ([System.Diagnostics.EventLog]::SourceExists($source) -eq $false) {
                [System.Diagnostics.EventLog]::CreateEventSource($source, "Application")
            }
    }
}

另请参阅Microsoft KB 2028427 无法从ASP.NET或ASP应用程序写入Windows事件日志

在IIS7中,您可以将“NETWORK SERVICE”指定为应用程序池的标识(您可能会发现ApplicationPoolIdentity是默认值),或者您可以为每个应用程序池创建一个新用户,并在该“自定义帐户”上设置权限。请参见为应用程序池指定标识(IIS 7) - Grokodile
6
只有在您在IIS上重新启动应用程序后,更改才会生效。 - Zé Carlos
8
我已授权IIS_IUSRS读写eventlog键,并读取Security键。我的产品需要在eventlog键上具有写入权限,因为它会创建自己的事件源。 - duck9
1
duck9适用于IIS8,更多详情请参见此处:https://dev59.com/BXRB5IYBdhLWcg3wH0WW。 - thedrs
1
请参考http://serverfault.com/a/81246/219898,了解有关应用程序池用户和相关权限的信息-以获取此解决方案。感谢@Michael Freidgeim-提供的大力帮助。 - Anthony Horne
显示剩余4条评论

65
问题在于 EventLog.SourceExists 尝试访问 EventLog\Security 键,而这个访问权限仅限管理员。
一个常见的 C# 程序写入日志到 EventLog 的例子是:
string sSource;
string sLog;
string sEvent;

sSource = "dotNET Sample App";
sLog = "Application";
sEvent = "Sample Event";

if (!EventLog.SourceExists(sSource))
    EventLog.CreateEventSource(sSource, sLog);

EventLog.WriteEntry(sSource, sEvent);
EventLog.WriteEntry(sSource, sEvent, EventLogEntryType.Warning, 234);

然而,如果程序没有管理员权限并且在 EventLog\Application 下未找到该键,则以下行将失败,因为 EventLog.SourceExists 将尝试访问 EventLog\Security
if (!EventLog.SourceExists(sSource))
    EventLog.CreateEventSource(sSource, sLog);

因此,推荐的方法是创建一个安装脚本,该脚本创建相应的键,即:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\dotNET Sample App

然后可以删除这两行。

您还可以创建一个 .reg 文件来创建注册表键。只需将以下文本保存到文件 create.reg 中:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Application\dotNET Sample App]

1
这正是我为所有服务所做的事情。我相信这是正确的做法。在我使用事件日志的每个服务中,我都有一个像上面那样的.reg文件。需要注意的一点是,该文件必须保存为Unicode-32(cp 1200)。 - Valo
这个答案描述了错误背后的真正原因。checkExists 尝试枚举整个键,如果存在,则 checkExists 可以正常工作。 - DanO
EventLog\Security 这是函数的关键,确保您拥有该权限。 - Princa
这是错误信息的一个原因。另一个原因只是自定义源日志不存在。 - Suncat2000

48
解决方案是在EventLog/Security键上给"Network Service"帐户读取权限。

1
我看到周围有类似的解决方案。但我只是想知道为什么会这样。因为我可以看到很多服务都以NetworkService身份登录,它们必须能够读取事件日志/安全性。那么为什么需要为NetworkService添加权限呢? - h--n
12
对于不经常浏览注册表的人,这个链接可能会有所帮助:http://social.msdn.microsoft.com/forums/en-US/windowsgeneraldevelopmentissues/thread/00a043ae-9ea1-4a55-8b7c-d088a4b08f09/ - Allan
Allan,不错的链接。被接受答案中的第三点很重要,而且已经让我吃过一次亏了。即在父EventLog注册表键上授予权限并不会传播到“无法访问的日志”,例如安全和虚拟服务器,尽管它们是注册表中的子键。如果您想要完全访问事件日志,则必须在父事件日志级别和子安全级别上授予权限。 - Ben Barreth
1
只有在您重新启动IIS上的应用程序后,更改才会生效。 - Zé Carlos
对于那些试图复制/粘贴的人,请确保单词“Network Service”之间有一个空格。 - Chris Fremgen

8
对我来说,只有授予“NetworkService”对整个“EventLog”分支的“读取”权限才有效。

这并不是很相关,因为对于诸如“安全”或“虚拟服务器”之类的子键,需要单独授予读取访问权限,因为权限已设置为不从父键继承。 - serge

8

我最近在一个作为定时任务运行的.NET控制台应用程序中遇到了这个异常,我的目标其实和你差不多,就是创建一个新的事件源并写入事件日志。

最终,为我正在运行任务的用户设置以下键的完全权限解决了问题:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Application
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Security
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog

3
你救了我的一天。顺便提一下,在 "eventlog\Application" 和 "eventlog\Security" 上读取权限就足够了;只有在 "eventlog" 根目录上才需要完全控制权限。 - Ruud Helderman

7
我在使用VS2010开发控制台程序时遇到了一个非常类似的问题(从XP升级到VS2008)。 我的程序使用EnLib进行一些日志记录。 错误是因为EntLib没有权限注册新的事件源而触发的。
所以,我以管理员身份启动了编译好的程序:它注册了事件源。 然后我回到VS中进行开发和调试,没有出现问题。
(您也可以参考http://www.blackwasp.co.uk/EventLog_3.aspx,这对我很有帮助。)

7

我尝试了几乎所有方法来解决这个问题...我在这里分享帮助我的答案:

另一种解决方法:

  • 在IIS控制台中,进入管理您的站点的应用程序池,并注意运行它的身份(通常为Network Service)
  • 确保此标识可以读取KEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog(右键单击,授权)
  • 现在将此应用程序池的标识更改为Local System,应用并切换回Network Service

凭据将被重新加载,EventLog将可达

http://geekswithblogs.net/timh/archive/2005/10/05/56029.aspx,感谢Michael Freidgeim。


将应用程序池从“ApplicationPoolIdentity”更改为“LocalSystem”解决了我创建/读取事件日志的问题。 - majestzim

6
当您使用 System.Diagnostics.EventLog.WriteEntry("SourceName", "ErrorMessage", EventLogEntryType.Error); 时,需要在regEdit下的HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Application中创建一个新的带源名称的键。
因此,基本上您的用户没有权限创建该密钥。根据应用程序池高级设置中Identity值所使用的用户,可以执行以下操作:
  1. 运行RegEdit并转到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog
  2. 右键单击EventLog键,然后选择Permissions选项

    3.添加具有完全控制访问权限的用户。

    -如果您使用的是"NetworkService",请添加NETWORK SERVICE用户

    -如果您正在使用"ApplicationPoolIdentity",请添加IIS APPPOL {您的应用程序池名称}(在搜索用户时使用本地计算机位置)。

    -如果您正在使用"LocalSystem",请确保该用户具有管理员权限。这不推荐用于漏洞。

  3. 重复步骤1到3,以获取HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Security

对于使用Visual Studio进行调试,我使用"NetworkService"(它是ASP.NET用户),当网站发布时我使用"AppicationPoolIdentity"。

4

我遇到了同样的问题,但我必须向上一级赋予每个人对HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\键的完全访问权限,而不是向下到安全性,这为我解决了问题。


1
还可以尝试将应用程序设置为以LocalSystem运行,这样注册表键就会被创建,然后您可以在之后改回NetworkService。 - demoncodemonkey

4

在Windows 7 64位系统上出现了同样的问题。以管理员身份运行解决了这个问题。


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