如何降低 WCF 命名管道的完整性
我有一个用 C# 编写的 Internet Explorer 加载项,它通过 WCF 命名管道与 .NET 桌面应用程序进行通信。桌面应用程序为 netNamedPipeBinding 创建 ServiceHost,并且 IE 加载项的每个实例都会创建一个 ChannelFactory 来与应用程序通信。在 Windows XP 下一切正常,但在 Windows 7 中 IE 的保护模式下会引发异常。
System.ServiceModel.CommunicationException:无法连接到端点“net.pipe://localhost/MyApp.MyID”。 ---> System.IO.PipeException:“\.\pipe...guid...”存在管道端点,但连接失败:访问被拒绝。 (5, 0x5)
在保护模式下运行加载项是我必须支持的方案。我的理解是,如果我降低命名管道的完整性级别,那么我的 IE 加载项将被允许通过它进行通信。我的问题是如何做到这一点。我已经设置了使用 WCF 的功能,并且希望保持这种状态。我可以让 WCF 创建完整性级别较低的命名管道吗?我需要编写什么代码来实现这一点?
I have an Internet Explorer add-in, written in C#, which talks via a WCF named-pipe to a .NET desktop application. The desktop app creates the ServiceHost for the netNamedPipeBinding, and each instance of the IE add-in creates a ChannelFactory to talk to the app. Everything works fine under Windows XP, but an exception is thrown under IE's protected mode in Windows 7.
System.ServiceModel.CommunicationException: Cannot connect to endpoint 'net.pipe://localhost/MyApp.MyID'. ---> System.IO.PipeException: A pipe endpoint exists for '\.\pipe...guid...', but the connect failed: Access is denied. (5, 0x5)
Running the add-in under protected mode is a scenario I must support. My understanding is that if I lower the integrity level of the named-pipe, then my IE add-in will be allowed to talk through it. My question is how to do that. I have things setup to use WCF, and would preferably like to keep it that way. Can I make WCF create the named pipe with the lower integrity level? What code do I write to make that happen?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为这是不可能的。
问题在于,必须在创建命名管道时提供的安全描述符中指定完整性标签。在标准 NetNamedPipeBinding 中,对 CreateNamedPipe 的调用发生在内部 WCF 类 System.ServiceModel.Channels.PipeConnectionListener 的私有
CreatePipe()
方法内。我看不出有什么方法可以改变它指定管道初始安全描述符的方式。请参阅此问题和答案< /a> 概述我们需要实现的目标。
从头开始编写自定义命名管道传输绑定元素似乎是目前解决此问题的唯一方法,如果失败,我们只能等待 Microsoft 在 WCF 的未来版本中添加一些支持功能。如果您有权访问 Microsoft Connect,则可以将您的声音添加到请求此功能的其他人。
编辑:
我太悲观了。我现在找到了一种方法来做到这一点。
关键是,事实证明,在创建管道时,您不必在安全描述符中指定完整性标签 - 但您必须使用打开侦听器时从 CreateNamedPipe 返回的句柄来修改 SACL - 即管道的第一个服务器端句柄。使用任何其他句柄,尝试添加完整性标签总是会失败,因为
CreateNamedPipe
的dwOpenMode
标志参数会重载使用其中一位来表示这两个FILE_FLAG_FIRST_PIPE_INSTANCE
和WRITE_OWNER
。我们需要后者的访问权限才能添加完整性标签,但前者的存在会导致调用在除第一个管道实例之外的任何管道实例上失败。掌握第一个管柄并不是一件容易的事。 WCF 将其存储在 System.ServiceModel.Channels.PipeConnectionListener.PendingAccept 类型的实例中,该实例存储在由管道连接侦听器维护的列表中。连接侦听器与通道侦听器(可以通过重写绑定元素的 BuildChannelListener 方法直接获取)不同,并且更难获取。它涉及使用反射来定位端点的 TransportManager(它保存对端点的连接侦听器的引用)的英雄行为,然后沿着连接侦听器链(根据跟踪等的配置而变化)进行工作,直到找到管道连接侦听器。如果幸运的话,可以在侦听器的待处理接受列表中找到第一个管道句柄(尽管这里存在竞争条件 - 如果客户端在我们获得句柄之前连接,它将永远消失)。
一旦句柄可用,降低完整性以允许低完整性客户端与服务进行通信只需在句柄上调用
SetSecurityInfo
来添加完整性标签即可。我计划在 我的博客< /a> 很快。
I don't think this is going to be possible.
The problem is that the integrity label has to be specified in the security descriptor provided when the Named Pipe is created. In the standard NetNamedPipeBinding, that call to
CreateNamedPipe
happens inside the privateCreatePipe()
method of the internal WCF classSystem.ServiceModel.Channels.PipeConnectionListener
. I can't see a way to change how it specifies the initial security descriptor for the pipe.See this question and answer for an outline of what we need to achieve.
Writing a custom named pipe transport binding element from scratch seems like the only way at present to get round this, failing which we'll just have to wait for Microsoft to add some enabling features in a future version of WCF. If you have access to Microsoft Connect, you could add your voice to the others requesting this feature.
EDIT:
I was too pessimistic. I have now found a way to do this.
The key was that it turned out you don't necessarily have to specify the integrity label in the security descriptor when the pipe is created - but you do have to modify the SACL using the handle returned from CreateNamedPipe when the listener is opened - i.e. the very first server-side handle to the pipe. Using any other handle, the attempt to add the integrity label always fails, because the
dwOpenMode
flag parameter toCreateNamedPipe
overloads the use of one of the bits to mean bothFILE_FLAG_FIRST_PIPE_INSTANCE
andWRITE_OWNER
. We need the latter access permission in order to add the integrity label, but the presence of the former causes the call to fail on any but the first pipe instance.Getting hold of the first pipe handle is not a trivial undertaking. WCF squirrels it away in an instance of the type
System.ServiceModel.Channels.PipeConnectionListener.PendingAccept
, stored in a list maintained by the pipe connection listener. The connection listener is not the same thing as the channel listener (which can be grabbed straightforwardly by overriding theBuildChannelListener<>
method of a binding element), and it is much harder to get at. It involves heroics using reflection, to locate the TransportManager for the endpoint, which holds a reference to the endpoint's connection listener, and then working down a chain of connection listeners (which varies according to configuration of tracing etc) until the pipe connection listener is found. If we are lucky the first pipe handle can then be found in the listener's pending accept list (though there is a race condition here - if a client connects before we get hold of the handle, it will be gone forever).Once the handle is available, lowering the integrity to allow low integrity clients to communicate wth the service is just a matter of calling
SetSecurityInfo
on the handle to add the integrity label.I plan to cover this is some detail on my blog soon.