安全透明方法X尝试访问安全关键方法Y失败。

24

我有一个相对稳定的服务器应用程序版本,已经在数十个客户端部署了近一年。

最近有一个新客户设置了该应用程序,并出现了以下错误:

System.MethodAccessException: 安全透明方法 [SomeMethod] 试图访问安全关键方法 [SomeOtherMethod] 失败。

SomeMethod和SomeOtherMethod都是我编写的程序集中的方法,构建于.NET 4,并在Windows服务内运行。如果有区别的话,SomeOtherMethod确实引用了第三方程序集(EntLib 4.1)中构建于.NET 2.0的类型。查看EntLib 4.1的代码时,我确实看到他们使用了SecurityTransparent和APTC属性,但这从未在其他客户端中引起过问题。

这些程序集已经从.NET 2.0 CLR升级,但很久以前就完成了。这段精确的代码在其他客户端上运行得很好,而且我在任何地方都没有显式地使用APTC属性或SecurityCritical属性。

这使我得出结论,这可能是一个配置问题,或者是.NET Framework补丁问题。是否发布了.NET的补丁,会导致此破坏性变化?是否有某个配置设置可以强制执行此类型的检查,默认情况下关闭但我的客户端可能已经启用了?

最后一点,我的服务利用SSRS RDLC生成PDF。由于.NET 4中的一些更改,我必须通过以下配置强制服务使用传统的安全策略:

  <runtime>
    <NetFx40_LegacySecurityPolicy enabled="true" />
  </runtime>

要了解我为什么需要这样做的更多细节,请参阅此stackoverflow帖子:Very High Memory Usage in .NET 4.0

重要的是,我在所有其他客户端都执行此操作。只有这一个客户端存在问题。

4个回答

24

唉,微软模式和实践团队负责企业库的模式和实践采用的方式和做法相当糟糕。好吧,异常是准确的,你不能从被标记为“我一定会检查安全性”的代码中调用一个被标记为“嗯,我不会检查安全性,所以不要浪费 CPU 周期来检查它”的方法。这种做法与 Java 中使用的异常规范一样不可扩展。CAS 非常有用,但诊断异常是一个很大的头疼,并且通常涉及到你无法拥有和修复的代码。这也是它在 .NET 4 中被弃用的一个重要原因。

编辑完成。对问题进行一次尝试,你需要找出为什么要在这里执行 CAS。最简单的解释是服务没有在完全信任的情况下运行。最简单的解释是客户端没有将服务安装在本地硬盘上。或者即使在本地程序集上运行代码,非常谨慎的管理员也可能更喜欢在“不信任它”模式下运行。这需要使用 Caspol.exe 进行配置,其命令行选项与 CAS 一样神秘。如果怀疑是因为位置不受信任,请按照此博客文章中所示运行 Caspol。或者只需将服务部署在本地,这样默认的“我信任你”就适用了。

根据OP发现的真正原因进行编辑:注意来自不受信任的互联网或网络位置下载文件时会添加的备用数据流。该文件将获得一个名为"Zone.Identifier"的流,该流记录了它来自哪里,并带有"ZoneId"值。这个值会覆盖从存储位置获取的信任,通常将其放在Internet区域中。使用资源管理器,右键单击文件并单击“解除锁定”以删除该流。在确认您可以信任该文件后 :)


1
这有道理。我今天会检查一下。我最初的想法实际上是由于 Windows 中的功能阻止了某个汇编程序,该功能通过标记通过电子邮件或 IE 下载的文件为不安全来发挥作用。我之前就遇到过这种情况。 - RMD
4
你的回答非常有用。事实上,问题是由于阻塞了程序集所导致的。移除该文件的阻塞(属性 -> 解除阻止)解决了这个问题。 - RMD
2
@RMD 谢谢!该死的Windows。 - JefClaes

13

当我使用他们的ServiceModelEx库运行从http://www.idesign.net/下载的WCF示例时,我遇到了类似的问题。 我在ServiceModelEx项目的AssemblyInfo.cs中注释掉了下面的这行。

//[assembly: AllowPartiallyTrustedCallers]

而且它对我很有效。


我正在一个WinForms应用程序中使用ClickOnce部署的库。正如@hans-passat所描述的那样,ClickOnce是一个带有CAS的野兽。幸运的是,我有库的源代码,因此注释掉上面的那行代码就为我解决了这个问题。 - bizl
谢谢 - 经过大量搜索,这对我有用。看起来,如果您的某些程序集在其AssemblyInfo.cs / .vb文件中具有此指令,而其他程序集没有,则.NET会感到困惑 - 删除所有实例似乎可以解决问题。 - CResults
这是一个我继承的旧服务... 不确定为什么它停止工作了,但是这个方法可以解决问题... - Poat

10

如果有帮助到其他人,我发布我的解决方案:

1)在AssemblyInfo.cs上,删除/注释掉[assembly: SecurityTransparent]行。

2)执行实际工作的类和方法被标记为[SecuritySafeCritical],在我的情况下建立一个网络连接:

[SecuritySafeCritical]
public class NetworkConnection : IDisposable
{
    [SecuritySafeCritical]
    public NetworkConnection(string networkName, NetworkCredential credentials)
    {
        .............
    }
}

3) 调用方的类和方法被标记为 [SecurityCritical]:

[SecurityCritical]
public class DBF_DAO : AbstractDAO
{
    [SecurityCritical]
    public bool DBF_EsAccesoExclusivo(string pTabla, ref ArrayList exepciones)
    {
        ....
        using (new NetworkConnection(DBF_PATH, readCredentials))
        {
            ....
        }
    }
}

谢谢Jhollman。我遇到了同样的问题。这帮助我解决了。 - TrieuH

0
在我的情况下,当我在解决方案中管理NuGet包时,有一个问题是某个包覆盖了主网站项目中的System.Web.Mvc程序集版本绑定。将其设置回4.0.0.0(我安装了5.0)。我没有注意到这个变化,因为Mvc v4.0已经安装并可以通过GAC访问。将其设置回去即可。

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