On of the top benefits to using NetNamedPipeBinding is that we provide an on-box guarantee for your messages. The on-box guarantee is enforced by Denying the Network Security Identifier (SID: S-1-5-2) access to our named pipe. This is the most secure, safest way of ensuring that you are not exposed to connection attempts from the network.
There is a price to pay for this assurance, and it comes in the form of impersonation support in middle-tier scenarios. The short version is that if you are using impersonation, you can only perform messaging to another Named Pipe endpoint using that impersonated token if you negotiate to NTLM in certain restricted conditions.
Here are the gory details:
Over Kerberos, any client/server authentication will always generate Network SID in the access token. When the server authenticates a client all the relevant information is included in the Kerberos ticket presented by the client, and the ticket doesn’t contain information on the location of the client (this is simply not part of the protocol at this point). So even if both client and server are on the same machine, everything works exactly the same as in the remote case, and the resulting access token has the Network SID (because the protocol has no way of knowing that you are on-box).
Over NTLM, if the client uses the current credentials there is an optimization where NTLM references the existing token under which the client process is running instead of generating a new token. In this case you won’t see the Network SID, because the original token was generated by an interactive logon attempt. If your client is configured with specific credentials, then SSPI will consider this a network logon.
When using WCF, Windows authentication is performed through SSPI-Negotiate, which in most cases will select Kerberos as the actual authentication mechanism. However, if the target SPN passed to SSPI is a well formed SPN for the local computer account (e.g. host/[dns machine name]) then Negotiate will use NTLM (loopback optimization) and the access token will not have the Network SID (and therefore will be usable with NetNamedPipes).
This makes me quite uncomfortable for a number of reasons.
First, it seems to me that under the tenets of SOA, the issue of which connections are acceptable is a matter for policy, not channel. I would expect that the default binding for the named pipe channel would have a policy restricting the other endpoint to one on the same box, because even though named pipes work across boxes, TCP is a more efficient choice in that scenario. However, I could see a situation in which it would make sense to override this policy. Imagine a Windows service that spawns numerous instances of executables to handle work (as IIS does) and uses web services to send messages for assigning work. The named pipe channel would make the most sense. But if on a farm, the services needed to occasionally communicate to coordinate load balancing, you might not want to create a separate binding or a separate service, depending on certain implementation details. In any case, I wouldn’t want the architecture to enforce that named pipes can only be used on-box.
Second, using SIDs to restrict endpoints seems to be a mismatch. I can see that named pipes don’t give you any other way to do it. However, I could see creating a custom security header in soap that would pass some information that could only be known by a client on the same box.
Third, based on your description above, I suspect that if I were running a process under a domain account rather than a local account, I would be unable to used the named pipes channel. This would completely screw me. For various reasons, it is often not an option for me to run a process under a local account, and I would not like it if that denied me the ability to use the named pipe channel.
There are some transports which have intrinsic topology restrictions. For example, if I was writing an in-process or in-appdomain channel, you wouldn’t be able to contact that endpoint outside of the process/endpoint in question. Which endpoints you decide to publish is certainly a matter of policy. While it is technically possible to use named-pipes cross-machine, we made a conscious decision (based on customer requests) to restrict this usage to on-machine. Users wanted a way to ensure their service is not accessible off-machine. Furthermore, they wanted this assurance to be complete. If we used a custom security header then you are exposed to an attack where code on-machine can pass this “local secret” off box and then your service is accessible off-machine. For defense in depth we actually have a variation of this which is the pipe name is stored in shared memory and it is that shared memory name which is referenced by net.pipe://xxxx. But the only true way to ensure you are not accessible off box is to deny Network SID.
You could argue that we could have added a knob “bool AllowOffMachineAccess” which allowed the user to toggle our behavior, though it would also require an overhaul of our net.pipe addressing scheme.
I don’t understand your assertion that you cannot used named pipes with a domain account. Our named pipe tranpsort can be used by any account on the box. The restriction I am talking about is only in effect when using named pipes while running under an impersonated token.
I’m sorry, I don’t understand what you are saying here.
Here’s my story:
I am hosting a WCF service in a Windows Service, running under the local Network Service account. The WCF service exposes a single endpoint with a standard netNamedPipeBinding, no binding configuration added.
On the same box I have a unit test, running under my credentials that calls the netNamedPipe service endpoint.
The security negotiation results in a kerberos token in the service. The service is able to impersonate the caller and call a endpoing on another service with a netTcpBinding, again same machine.
In the second service, if I look at the claimset, I see that one of the claims is:
From what you’re saying, seems like my results shouldn’t be possible. Do I misunderstand, what you’re saying here?
Here’s an update: To make sure, I moved my back-end service, the one called using an impersonated user account, to another box. I am still able to reach the back-end service.
So, my client application is running under my user account; the middle-tier service is on the same box running under the Network Service account and the back-end service is on another box running under a domain service account.
The client connects to the middle-tier using a netNamedPipe binding. The middle tier impersonates the caller and connects to the back-end service using a wsHttpBinding with message security (clientCredentialType=Windows).
The back-end service authenticates the caller as the impersonated user and executes without error. Is this the expected bahavior?
I see you posted this back in March 2006, has something changed since Indigo became WCF? I sure would like to understand this, so I don’t get bit later when some “small” change breaks my app.