我有一个应用程序需要由第二个应用程序调用。这些应用程序需要无需配置(最好无需触及注册表)即可找到彼此,并在终端服务环境中正常运行。我听说使用命名管道的 .net 远程处理可能是实现此目的的一种方法,但我不明白如何限制管道只能在创建它的会话中访问。谢谢
更新:我对 WCF 很好,问题不是特定于远程处理,而是如何将命名管道设置为会话本地。
I have an application that needs to be called upon by a second application. These applications need to find each other without configuration (preferably without touching the registry) and function in a terminal services environment properly. I have heard that .net remoting using named pipes may be a way to accomplish this but I do not understand how to limit the pipe to be accessible only within the session that created it. Thanks
Update: I am fine with WCF, the question is not specific to remoting, but how to set a named pipe to be local to a session.
发布评论
评论(3)
如果您的应用程序在 Windows Vista 或 Windows 7 上运行,并且您正在使用 WCF NetNamedPipeBinding,则您将自动获得只能从同一会话中访问的服务,前提是实现管道服务端的进程没有SeCreateGlobalPrivilege 权限。实际上,这通常意味着服务器可以是在交互式会话中启动的任何程序,前提是它不是以管理员身份运行启动的。
其原因与 WCF 创建的命名共享内存对象有关,该对象是为了向潜在客户端发布实际管道名称(GUID)而创建的。 我在我的博客上解释了这种机制。如果服务进程具有SeCreateGlobalPrivilege,则在所有会话可见的Global kernel命名空间中创建此发布对象;如果没有此权限,则在本地内核命名空间中创建该对象,该对象仅在同一会话中可见。请注意,这并不能提供绝对的安全性:如果管道名称 GUID 以某种方式以其他方式公开,则理论上可以从另一个会话访问命名管道本身(使用本机 API 调用而不是 WCF 客户端堆栈)。
如果您需要支持较早的操作系统,或者如果您希望管道本身具有绝对的安全性,则需要在 WCF 服务通道堆栈创建管道后修改管道上的 DACL 来显式实现限制。这需要对标准绑定进行一些修改,我将展示如何完成此操作在这里。您还需要编写一些 P/Invoke 代码(这不是特别简单)来发现正确的登录会话 SID,以便在 DACL 中创建 ACE。在 .NET 4 中,WCF 服务堆栈本身会发现并使用登录会话 SID 来限制创建新管道实例的权限,因此您可以使用 Reflector 来查看它是如何执行此操作的 - 请参阅:
System.ServiceModel。 Channels.SecurityDescriptorHelper.GetProcessLogonSid()
。If your application is running on Windows Vista or Windows 7, and you are using the WCF NetNamedPipeBinding, you will automatically get a service which is only accessible from within the same session PROVIDED that the process which implements the service end of the pipe does not have the SeCreateGlobalPrivilege privilege. In practice, this usually means the server can be any program started in the interactive session provided that it is not started with Run As Administrator.
The reason this is so concerns the named shared memory object which WCF creates to publish the actual pipe name (a GUID) to potential clients. I explain this mechanism on my blog. If the service process has SeCreateGlobalPrivilege, this publishing object is created in the Global kernel namespace visible to all sessions; if it doesn't have this privilege, the object is created in the Local kernel namespace visible only within the same session. Note that this doesn't provide absolute security: the named pipe itself could in theory be accessed from another session (using native API calls rather than the WCF client stack) if the pipe name GUID was somehow disclosed another way.
If you need to support an earlier OS, or if you wanted absolute security on the pipe itself, you would need to implement the restriction explicitly by amending the DACL on the pipe after the WCF service channel stack has created it. This requires some tinkering with the standard binding, and I show how this can be done here. You would also need to write some P/Invoke code, which is not particularly straightforward, to discover the correct logon session SID for which to create the ACE in the DACL. In .NET 4 the WCF service stack itself discovers and uses the Logon Session SID to restrict the permission to create new pipe instances, so you could use Reflector to have a look at how it does this - see:
System.ServiceModel.Channels.SecurityDescriptorHelper.GetProcessLogonSid()
.我一直在研究这个确切的问题。到目前为止,我发现的最佳解决方案(但尚未尝试)是使用 会话 ID。
I have been looking into this exact problem. The best solution I have found so far (but not tried yet) is to create a unique named pipe name by using the session id.
我建议使用 Windows Communication Foundation 来实现此目的。
您可以选择在不使用注册表的情况下配置所有不同的通信选项,包括使用命名管道、套接字等。
I would recommend using Windows Communication Foundation for this.
You'd have the option of configuring, without using the registry, all of the different communication options, including using named pipes, sockets, etc.