从IIS应用程序

时间:2018-05-06 20:12:58

标签: wcf named-pipes asp.net-4.0 code-access-security

我们有一些遗留的Web应用程序代码,我们正在更新并移植到.NET 4.0运行时。

代码位于类库中,并使用WCF连接到命名管道端点。

当我从控制台应用程序启动连接时,一切正常。

当我从Web应用程序启动连接时,我收到一个例外:

Access is denied
Server stack trace:
  at System.ServiceModel.Channels.AppContainerInfo.GetCurrentProcessToken()
  at System.ServiceModel.Channels.AppContainerInfo.RunningInAppContainer()
  at System.ServiceModel.Channels.AppContainerInfo.get_IsRunningInAppContainer()
  at System.ServiceModel.Channels.PipeSharedMemory.BuildPipeName(String pipeGuid)
  at System.ServiceModel.Channels.PipeSharedMemory.get_PipeName()
  at System.ServiceModel.Channels.PipeConnectionInitiator.GetPipeName(Uri uri, IPipeTransportFact… Object[] , Object[] )
  at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
  at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
  at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
  at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc)
  at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

错误源自托管代码和非托管代码之间的边界,其中存在对advapi32.dll的调用:

[SecurityCritical]
private static SafeCloseHandle GetCurrentProcessToken()
{
  SafeCloseHandle TokenHandle = (SafeCloseHandle) null;
  if (!UnsafeNativeMethods.OpenProcessToken(UnsafeNativeMethods.GetCurrentProcess(), TokenAccessLevels.Query, out TokenHandle))
    throw System.ServiceModel.FxTrace.Exception.AsError((Exception) new Win32Exception(Marshal.GetLastWin32Error()));
  return TokenHandle;
}

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr ProcessHandle, TokenAccessLevels DesiredAccess, out SafeCloseHandle TokenHandle);

网络上的各种主题建议删除元素或设置impersonate="false"

<system.web>
  <identity impersonate="true"/>
</system.web>

事实上,这可以解决我的问题。但是,我不确定这可能会对应用程序产生什么副作用(SharePoint 2016),因此我不愿意简单地删除此属性。

SecurityCritical属性给了我一些提示,或许这与.NET 2.0和.NET 4.0之间的CAS模型的变化有关。代码安装在GAC中,因此它应该在完全信任的情况下运行,但我还是试了一下。

我还尝试将[SecuritySafeCritical]添加到方法中,并且调用IChannel.Open()的类无效。

我还尝试在程序集上添加[assembly: SecurityRules(SecurityRuleSet.Level1)],因为这应该会锁定到.NET Framework 2.0安全规则中。

我正在寻找任何其他见解和其他方法来尝试解决此问题。

与其他Stack帖子有一些相似之处:How to call net.pipe (named pipe) WCF services while impersonating in a Windows Service除了没有明确的冒充发生,所以我不确定修复是否适用。

另外需要注意的是,当我尝试调用System.Diagnostics.Process.GetCurrentProcess()时,会抛出相同的错误。当尝试获取当前执行过程的句柄时,错误也会产生。

1 个答案:

答案 0 :(得分:0)

我得出的结论是,这个问题与.NET 4.0中System.ServiceModel的内部结构有关。

最初,我认为这可能与Server 2016 UAC或.NET 4.0 / IIS 10 Web应用程序运行时设置(例如.NET 2.0 vs .NET 4.0 CAS模型)有关。我在.NET 3.5中创建了一个简单的Web应用程序,并尝试调用Process.GetCurrentProcess().Handle。我在新服务器上运行了它,并且它失败并且#34;访问被拒绝&#34;错误。

我把它带到旧服务器(Windows Server 2008 R2,.NET 3.5)并在那里运行它,希望这可以工作,而且看起来也很失败。所以我在3.5中浏览了System.ServiceModel的源代码,发现没有AppContainerInfo因此很可能3.5代码根本没有进行相同的Win32 API级别调用。

我的结论是我们之前没有遇到此错误,因为旧的3.0库不需要从advapi32.dll调用API或者有其他机制来创建管道名称。

确实,这是3.0 {&#34;中PipeConnectionInitiator.GetPipeName的实施的前几行:

internal static string GetPipeName(Uri uri)
{
  string[] strArray = new string[3]
  {
    "+",
    uri.Host,
    "*"
  };
  bool[] flagArray = new bool[2]{ true, false };
  for (int index1 = 0; index1 < strArray.Length; ++index1)
  {
    for (int index2 = 0; index2 < flagArray.Length; ++index2)
    {

以下是4.0中的前几行:

internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
{
  AppContainerInfo appContainerInfo = PipeConnectionInitiator.GetAppContainerInfo(transportFactorySettings);
  string[] strArray = new string[3]
  {
    "+",
    uri.Host,
    "*"
  };
  bool[] flagArray = new bool[2]{ true, false };
  string str1 = string.Empty;
  string str2 = (string) null;
  for (int index1 = 0; index1 < strArray.Length; ++index1)
  {
    for (int index2 = 0; index2 < flagArray.Length; ++index2)
    {
      if (appContainerInfo == null || !flagArray[index2])

因此4.0实现需要访问执行OpenProcessToken

如果代码足够孤立,一个选项是使用程序集绑定重定向:

<runtime>
  <assemblyBinding>
    <dependentAssembly>
      <assemblyIdentity name="System.ServiceProcess" publicKeyToken="b77a5c561934e089" culture="neutral" />
      <bindingRedirect oldVersion="4.0.0.0" newVersion="3.0.0.0" />
    </dependentAssembly>            
  </assemblyBinding>
</runtime>

只需强制运行时绑定到旧版本。

不幸的是,该应用程序对System.ServiceModel 4.0有一些依赖性,所以切换它并不是那么简单。