我们在ASP.NET应用程序中调用System.IO.Packaging.Package.Open()。此外,在调用此程序之前,已经执行了Windows模拟,因为要打开的包存储在安全位置,并且需要模拟才能读取它。
问题是Package.Open()调用EventTrace.EasyTraceEvent(),后者又调用MS.Utility.EventTrace.IsClassicETWRegistryEnabled(),它引发了一个安全异常,即不允许请求注册表访问。
即使在Web.config中被特别禁用,也会发生这种情况。在调试和发布模式下。
因此我陷入了困境。需要模拟,因为文件(包)的存储方式使其只能由模拟的帐户访问。将其复制到不安全的位置会破坏安全性。
授予模拟帐户对注册表的访问权限会在另一个方向打开一个安全漏洞。除了一组特定的文件和文件夹之外,此帐户没有也不需要对任何其他系统资源进行任何访问。
我真正想要的是EventTrace从悬崖上一跃而下,但我不知道该怎么做。
有什么想法吗?
简短回答:使用流。执行模拟以打开流,结束模拟,然后将仍然打开的流传递给Package.open().
长答案:
-
错误的来源是EventTrace的静态类初始值设定项。它调用IsClassicETWRegistryEnabled(),后者反过来访问注册表。由于它在类初始值设定项中,这意味着无法禁用它,并且EventTrace在模拟时从根本上被破坏。
-
Package.Open()实际上是"新ZipPackage()"的包装。
-
ZipPackage是Package抽象类的密封实现。
-
ZipPackage没有公共构造函数。
-
ZipPackage反过来使用ZipArchive上的内部方法,ZipArchive位于MS.internal.IO.Zip命名空间中,也是一个密封类。
结论:
-
当模拟没有足够的注册表访问权限时,System.IO.Package会出现模拟问题。
-
System.IO.Package应被视为私有的Microsoft命名空间,而不是公共命名空间。
选项:
-
将文件移出安全区域,这样就不需要模拟。
-
当不需要模拟时加载文件,并以其他方式存储数据(例如:在数据库中)。
-
打开模拟下的流,结束模拟,然后对该流使用Package.Open()。
如果有人好奇,我们正在阅读的软件包是Visio 2013 VSDX文件。
我查看了.NET源代码引用,它需要访问的密钥是HKEY_CURRENT_USER\Software\Microsoft\Avalon.Graphics。授予"Everyone"对该特定密钥的读取访问权限没有我能想到的安全影响,并解决了问题。
下次我来这里解决这个问题时,我只想提醒我:
将应用程序池帐户添加为本地管理员。其效果是,is拥有读取所有被模拟用户的注册表的权限。
如果这不是一个选项,那么你需要在打电话之前恢复到Self。其效果是它停止了模拟,因此现在只需要获得读取当前用户的注册表的权限,而当前用户就是它自己。