如何降低WCF命名管道的完整性

我有一个用C#编写的Internet Explorer加载项,它通过WCF命名管道与.NET桌面应用程序进行通信。 桌面应用程序为netNamedPipeBinding创建ServiceHost,并且IE加载项的每个实例都创建一个ChannelFactory以与应用程序通信。 在Windows XP下一切正常,但在Windows 7的IE保护模式下会抛出exception。

System.ServiceModel.CommunicationException:无法连接到端点’net.pipe://localhost/MyApp.MyID’。 —> System.IO.PipeException:’\。\ pipe … guid …’存在管道端点,但连接失败:访问被拒绝。 (5,0×5)

在保护模式下运行加载项是我必须支持的方案。 我的理解是,如果我降低命名管道的完整性级别,那么我的IE加载项将被允许通过它进行通信。 我的问题是如何做到这一点。 我有设置使用WCF的东西,并希望保持这种方式。 我可以让WCF创建具有较低完整性级别的命名管道吗? 我写了什么代码才能实现这一目标?

我不认为这是可能的。

问题是必须在创建命名管道时提供的安全描述符中指定完整性标签。 在标准的NetNamedPipeBinding中,对CreateNamedPipe调用发生在内部WCF类System.ServiceModel.Channels.PipeConnectionListener的私有CreatePipe()方法中。 我看不到改变它如何指定管道的初始安全描述符的方法。

请参阅此问题和答案 ,了解我们需要实现的目标。

从头开始编写自定义命名管道传输绑定元素似乎是目前解决此问题的唯一方法,如果失败,我们只需要等待Microsoft在未来版本的WCF中添加一些启用function。 如果您有权访问Microsoft Connect,则可以将您的语音添加到请求此function的其他人 。

编辑:我太悲观了。 我现在找到了一种方法来做到这一点。

关键是事实certificate,在创建管道时你不必在安全描述符中指定完整性标签 – 但是你必须在打开监听器时使用从CreateNamedPipe返回的句柄来修改SACL – 即管道的第一个服务器端句柄。 使用任何其他句柄,添加完整性标签的尝试总是失败,因为CreateNamedPipedwOpenMode标志参数重载使用其中一个位来表示FILE_FLAG_FIRST_PIPE_INSTANCEWRITE_OWNER 。 我们需要后者的访问权限才能添加完整性标签,但前者的存在会导致调用在除第一个管道实例之外的任何管道上失败。

抓住第一个管道并不是一项微不足道的工作。 WCF将其放在System.ServiceModel.Channels.PipeConnectionListener.PendingAccept类型的实例中,它存储在由管道连接侦听器维护的列表中。 连接侦听器与通道侦听器不同(可以通过覆盖绑定元素的BuildChannelListener<>方法直接获取),并且更难以实现。 它涉及使用reflection的英雄,定位端点的TransportManager,它保存对端点的连接侦听器的引用,然后处理连接侦听器链(根据跟踪的配置等而变化),直到找到管道连接侦听器。 如果我们幸运的话,可以在侦听器的挂起接受列表中找到第一个管道句柄(虽然这里存在竞争条件 – 如果客户端在我们抓住句柄之前连接,它将永远消失)。

一旦句柄可用,降低完整性以允许低完整性客户端与服务进行通信只需在句柄上调用SetSecurityInfo来添加完整性标签。

我计划尽快在我的博客上介绍这个细节。