Security Briefs

Security in Windows Communication Foundation

Keith Brown

Contents

What CIA and Authorization Can Do for You
Choices in Windows Communication Foundation
Transport Security
Message Security
Credentials
Default Security in Standard Bindings
Discovering Client Identity
Installing a Certificate with HTTPCFG
Winding Up

W indows Communication Foundation performs a lot of the heavy lifting to make it easier for your service to provide the basic security features that most distributed systems need. The big three protections— confidentiality, integrity, and authentication (or CIA as I like to think of them) are provided by most standard Windows® Communication Foundation bindings. If you don't want these protections, you'll have to turn them off, because they are on by default.

What CIA and Authorization Can Do for You

So what's the role of each of these protections? Well, confidentiality makes sure that messages are encrypted so that an eavesdropper cannot read the contents of the messages. Integrity ensures that you use a keyed hash to perform a checksum on the contents of each message so you know that the message hasn't been tampered with since it was produced, or injected wholesale into the message stream by an attacker. And of course it makes no sense at all to encrypt a connection if the guy on the other end is the enemy! So in order to exchange the keys used for providing confidentiality and integrity, Windows Communication Foundation uses an authentication handshake, which not only helps the client and service discover these keys, but also helps them discover each other's identities.

Once the service knows the client's identity, it can then authorize the client to perform various operations. Authorization is performed by checking claims that the client has provided. Windows Communication Foundation provides a number of extensibility hooks that allow you to wire in the authorization policy of your choice and check the validity of the claims. You can use existing components like the ASP.NET membership and role providers and Authorization Manager (AzMan), which you can learn more about at msdn.microsoft.com/msdnmag/issues/03/11/AuthorizationManager. You can also use the standard .NET role-based security infrastructure with Thread.CurrentPrincipal, IPrincipal.IsInRole, and PrincipalPermissionAttribute. Or you can use the authorization policy framework in Windows Communication Foundation, centered around the IAuthorizationPolicy interface that provides fine grained control over the claims. You can also audit the actions of the client. You'll find that Windows Communication Foundation already audits many security events for you right out of the box.

Transparency is important when you're building a secure system. If the security features you build into the system aren't relatively transparent, users will be put off and will generally try to avoid using them. It's sad but true that as a security guy, my best work is always invisible! Windows Communication Foundation helps you achieve transparency in many ways, but one of the most important is through single sign-on. By tightly wiring into Windows domain authentication, you can leverage the user's domain login and reduce the number of credentials he needs to keep track of. Windows Communication Foundation also makes it easy to use federated identity, which allows partner organizations to have the same single sign-on experience even when they use Web services that your company exposes.

Another important aspect of security is robustness in the face of malformed input. Windows Communication Foundation can't really help with this, so it's still your responsibility to assume all input is evil until proven otherwise. And don't assume that an authenticated user won't send you malformed input, either! Even if you only service internal clients, you must remain robust. What I'm talking about here is resilience to attacks such as SQL injection, improperly formed resource names such as file paths, and, in some cases, even cross site scripting. When you hear people say, "Windows Communication Foundation is secure by default," understand that they are probably talking about CIA.

Choices in Windows Communication Foundation

Windows Communication Foundation pulls together the best features of the numerous communication stacks we used individually in the past. This means you have many choices to make when you expose a service, and some of these choices impact security. The biggest choice involves what binding to use. Do you want messages to be queued? Do you want interoperability or raw performance?

Always keep in mind that you don't need to make just one choice. You can expose a single service contract over as many bindings as you like; just expose a different endpoint for each binding. For example, you might expose a very simple WS-I basic profile binding over HTTPS to interoperate with existing partners in a supply chain. At the same time, you could expose a TCP endpoint that uses Windows authentication for local clients in your domain. This only works, however, if the user does not specify the ProtectionLevel property in the contract (using ServiceContract, OperationContract, MessageHeader, and so forth).

A typical standard binding has a lot of different knobs for adjusting security settings, but each binding has been carefully tuned to provide secure default settings for most of the scenarios you'll encounter. The two knobs you'll most often need to toggle are the security mode (transport versus message security) and the client credential type. These knobs are really important, so let's look at the right way to turn them.

Transport Security

When you're configuring security for a Windows Communication Foundation binding, the first choice you'll need to make is whether you want CIA to be provided at the transport level or at the message level. There are pros and cons to each choice.

If you configure wsHttpBinding for transport security, Windows Communication Foundation will not supply CIA for your messages. You're expected to run over HTTPS so that secure sockets layer (SSL) can provide these guarantees. In fact, Windows Communication Foundation will refuse to set up the connection unless an HTTPS URI is provided. If you're hosting inside IIS, you'll need to install an SSL certificate for the Web site. On the other hand, if you're hosting in your own process and using HTTP.SYS directly, you'll need to register a certificate with HTTP.SYS, either programmatically or via the command-line tool, HTTPCFG.EXE.

There are good reasons to use SSL. Because it's been around for so many years, SSL has been the subject of much analysis by cryptographers, and administrators have already figured out how to deploy it. There is hardware out there to accelerate it, reducing the load on your server's CPU. Best of all, if broad reach across platforms is your goal, there's no better choice today than using the WS-I basic profile over SSL (which of course would also mean using basicHttpBinding instead of wsHttpBinding).

For internal communication in a domain environment where both client and service use Windows Communication Foundation, netTcpBinding with transport security might be a better choice. It certainly performs a lot better given its binary encoding, and since it uses Kerberos exclusively by default, there's no need for certificates, although you will want to configure a service principal name (see the "Configuring a Service Principal Name" sidebar).

Message Security

Instead of providing CIA at the transport level, you can choose to push these details down into the SOAP messages themselves by using message security. The main benefit here is flexibility. The WS-Security and related specs for securing SOAP messages are very flexible; you can use any type of security credentials you want, largely independent of transport, as long as both client and service agree. In fact, you could even send multiple credentials, which becomes interesting in delegation scenarios where intermediaries are involved.

Take wsHttpBinding as an example. By default it uses message-level security, assuming the service and the client will identify and authenticate themselves using Windows credentials. By default, the body and most headers are signed to maintain the integrity of the message (specifically, it signs all WS-Addressing headers, and it encrypts and signs all application headers), and the body is encrypted. An attacker looking at a message trace would see the SOAP envelope in the clear, but the SOAP body would contain an <EncryptedData> element full of base64-encoded ciphertext.

Windows Communication Foundation also allows you to mix transport and message security. In this mode, confidentiality and integrity and the server's authentication are provided at the transport level (therefore the entire bytestream is encrypted, not just the message body), whereas client authentication is performed at the message level. The client can then use WS-Security to send any shape of credential that she wants. This mode gives you the performance and maturity of transport security with increased flexibility for choosing credentials.

Credentials

Once you've chosen either transport or message security (or mixed mode), and assuming you've not chosen a security mode of None, the next major decision is the shape of credential that the client and service will use. Windows Communication Foundation simplifies this by giving you only one knob, the client credential type, which also determines the service credential type that makes sense in each scenario. There are at least five options for client credentials, although some options may not be available in certain contexts.

The first option is None, where the client is anonymous. In this case the service uses a certificate to assure the client of the service's identity. This is similar to what you get when you visit a typical Web site over HTTPS.

The second option is UserName, where the client supplies a user name and password. Again, in this case the service uses a certificate to identify itself to the client. This certificate will also be used to encrypt the client's credentials for transmission to the service.

The next option is Windows, where both the client and service use a Windows account to authenticate. Windows Communication Foundation will negotiate Kerberos or NTLM, preferring Kerberos if a domain is present (NTLM does not actually authenticate the service to the client, only the client to the service). If you want to use Kerberos it's important to have the client identify the service with a service principal name (SPN) in config. If you're building a service for clients in a domain environment, you should definitely give them the option of sending a Windows credential. This allows them to use their existing Windows logon, giving you single sign-on for free!

Certificate is another option, where the service has a certificate and the client also has a certificate of her own. This is typical in many business-to-business scenarios today.Configuring a Service Principal Name

Configuring a Service Principal Name (SPN) for a service is easy. You can do it programmatically, or you can use a tool called SETSPN.EXE, which, like HTTPCFG.EXE, is also part of the support tools included with server versions of the operating system. The idea behind an SPN is straightforward: it simply decouples your client code from having to know exactly which account the service will be deployed under. By giving the client an SPN (which is just a string), when the client requests a ticket for the service account, she can request the ticket based on the SPN rather than the service account name.

Then an administrator can map that SPN onto the actual account name being used for the service using a tool like SETSPN. Here’s how it’s done:

setspn -A MyService/MyMachine MyDomain\ServiceAccount

This adds an SPN to the MyDomain\ServiceAccount user account in Active Directory. In this example the SPN is MyService/MyMachine. Now clients wanting to talk to the service called MyService on a machine called MyMachine can ask for a Kerberos ticket using an SPN formed from this information. It’s all about decoupling the client from the details of how the service is deployed.

If the administrator wants to run the service under a different account later, he’ll remove the old SPN mapping and add a new one, and clients will continue to function properly:

setspn -D MyService/MyMachine MyDomain\ServiceAccount setspn -A MyService/MyMachine MyDomain\OtherAccount

Finally, IssuedToken allows your service to accept a signed set of claims from a security token service (STS). While this might feel alien to you at first, this option is going to be important going forward as it enables federated identity scenarios and InfoCard. When you federate with a partner organization, you allow the partner to authenticate its own users via whatever technique makes sense for them. In the best case, this will allow users in the partner organization to use your service with single sign-on, even though they don't share an Active Directory domain or trust with you. The users in the partner organization are required to authenticate with an STS, which issues a signed Security Assertion Markup Language (SAML) token. You can either accept that token directly, or require that the token be presented to an STS in your own organization so it can evaluate the partner's claims and issue a second SAML token that you can use.

In either case, your service will receive a security token issued by an STS that you trust. Windows Communication Foundation will verify the signature and this trust and present the claims in the token to your service via an instance of ServiceSecurityContext. Your service can access this object while processing a request by simply reading the ServiceSecurityContext.Current static property. You can then use this information in order to perform both authorization and auditing.

The beauty of federation is that it automates existing trust relationships between partners: there's no need to issue shadow Windows accounts or certificates to each user in the partner organization when you federate. There are a lot of benefits to automating these relationships, too. Automation tends to reduce mistakes and latency, which means you're getting more accurate and up-to-date information about users in the partner organization. It also reduces cost for your IT staff because they don't need to provision user accounts for partners. Federated identity is an important topic that I'll spend more time on in a future column.

Default Security in Standard Bindings

The three most popular standard bindings are basicHttpBinding, wsHttpBinding, and netTcpBinding. The simplest and most interoperable is basicHttpBinding, which supports the WS-I basic profile. It's important to note that this particular binding doesn't provide CIA by default like most of the others. The most popular way to secure this binding is by simply running over HTTPS, due to the ubiquity of SSL. To do this, you'll need to tweak the binding to let Windows Communication Foundation know you'll be using transport security:

<bindings> <basicHttpBinding> <binding name="MyBindingTweaks"> <security mode="Transport"> <transport clientCredentialType="None"/> </security> </binding> </basicHttpBinding> </bindings>

Once you've done this, the easiest way to deploy is to host in IIS and turn on SSL support for your virtual directory (which will mean installing a certificate for the Web site if you've not already done so). Note that in this particular binding, I've allowed anonymous clients. If you're deploying in IIS and plan to require client certificates, change the clientCredentialType to Certificate.

The next binding, wsHttpBinding, uses message security by default, with WS-Security and WS-SecureConversation. The default client credential type is Windows, which makes it really easy to get started with; it simply uses the Windows logon of the client and service as credentials. One of the most common security tweaks to use on this binding is to switch it to use TransportWithMessageCredential. Here you'll use an HTTPS endpoint to provide accelerated server authentication, integrity, and confidentiality, while the client credential remains in the SOAP Security header for flexibility. One benefit of this technique is that the entire SOAP envelope is encrypted by the transport, including all the headers. It also lets you use hardware acceleration to offload Secure Sockets Layer/Transport Layer Security (SSL/TLS) from your server's CPU. There are some disadvantages, however, such as the lack of end-to-end security at the message level. The following shows how you'd apply this binding tweak to accept a SAML token at the message level, for example:

<binding name="MyBindingTweaks"> <security mode="TransportWithMessageCredential"> <transport clientCredentialType="None"/> <message clientCredentialType="IssuedToken"/> </security> </binding>

If you want raw speed for Web services on a Windows-based intranet, you should seriously consider using netTcpBinding, which encodes each SOAP envelope using a proprietary binary encoding of the XML Infoset instead of the traditional angle bracket encoding. By default this binding uses transport security with Windows credentials, and is very efficient. This is probably the closest you'll come to matching the performance and security model of DCOM. The default binding uses transport security with negotiated authentication. This negotiation attempts to use Kerberos, but if that doesn't work, it'll fall back and use the older NTLM protocol. Kerberos is a great choice if you're in a domain environment; in order to use it, you'll need both your service and clients to be running under domain accounts. You'll also want to configure a service principal name (SPN) for your service, as shown in the sidebar on this page. Clients will need to tweak their endpoint descriptions to include the identity of the service, which is the SPN the service registers. (This is not always required. If the service is hosted in IIS and is running under the NetworkService account, the SPN is provided automatically. Windows Communication Foundation will infer it correctly from the URL on the client side.) Here's the syntax for doing that in config. Note the servicePrincipalName element:

<client> <endpoint name="MyEndpoint" address="net.tcp://..." binding="netTcpBinding" contract="IFoo" > <identity> <servicePrincipalName value='MyService/MyMachine' /> </identity> </endpoint> </client>

When the client's Windows Communication Foundation plumbing asks the domain controller for a Kerberos ticket for the service, it'll use the name MyService/MyMachine to request the ticket, and as long as this SPN has been registered in Active Directory for the service's domain account, the client will be issued a ticket and Kerberos will be used. Otherwise, if Kerberos is available but the SPN is incorrect, an exception will be thrown. And if Kerberos is not available for the authentication to the service, the client will fail to get a ticket (which simply wastes a round-trip to the domain controller) and you'll head into NTLM fallback mode, which means even more round-trips for the fallback negotiation. Also, you'll miss out on features of Kerberos such as the potential to delegate client credentials.

Discovering Client Identity

By far the simplest way to discover a client's identity is to leverage Thread.CurrentPrincipal, which is the standard way in .NET that plumbing such as ASP.NET and Windows Communication Foundation communicate the identity of an authenticated client to your code. This rather magical static property will return different values depending on the thread that requests it. This allows you to have multiple threads servicing different clients, where each will see the identity of the client they are servicing without stepping on one another.

If you've specified Windows as your clientCredentialType, then Thread.CurrentPrincipal will point to a WindowsPrincipal, and you can see which groups the user belongs to by calling WindowsPrincipal.IsInRole. The only glitch here is that for security reasons you really should specify the fully qualified group name, which includes the domain or machine on which the group is defined, as shown in the following:

IPrincipal client = Thread.CurrentPrincipal; if (client.IsInRole(@"MyMachine\Managers")) { // allow client to do manager stuff }

When I'm building systems that authorize based on groups like this, I'll usually add some level of indirection that supplies the machine or domain name for the groups I'm using by looking in config. That simplifies deployment quite a bit.

I'll speak more about authorization in a later column—there's a lot to say about that subject. Note that Windows Communication Foundation doesn't always set Thread.CurrentPrincipal. It does that only if PrincipalPermissionAttribute is used or if the configuration says it should. Instead of relying on Thread.CurrentPrincipal, you should use ServiceSecurityContext.Current.WindowsIdentity to get the client's identity if one is available. Here's how you get the client's name in case you want to log what the client is doing:

string clientAccountName = ServiceSecurityContext.Current.WindowsIdentity.Name;

If the client is using an issued token credential to authenticate, you'll need to use ServiceSecurityContext.AuthorizationContext to pick up those details. If the client is authenticating with a certificate not mapped to a Windows account, ServiceSecurityContext.Current.PrimaryIdentity can be used. I plan to drill into these topics further in the future.

Installing a Certificate with HTTPCFG

If you want to use SSL but you're not going to host your service in IIS, you can use HTTP.SYS to provide SSL support. In order to use the SSL support in HTTP.SYS, you'll need to tell HTTP.SYS where to find its SSL certificate, and you can use the HTTP API to do this, or use HTTPCFG.EXE to call those APIs from the command line. HTTPCFG.EXE isn't installed by default, but you can get it by installing the support tools found in the SUPPORT\TOOLS directory on your operating system installation disk.

If you want to use a certificate with HTTP.SYS, you'll need to install it in the local computer store, not a user store. You can do this by running the Certificates Microsoft® Management Console (MMC), snap-in; when you add the snap-in just be sure to choose Computer Account when asked, then choose the computer where the service is deployed, or Local Computer if you're already logged into the computer where the service is deployed. Then import the certificate into the Personal store for that machine. The Personal store is where you normally put certificates for which you have a private key.

View the properties of the certificate and get the SHA-1 thumbprint of the certificate (see Figure 1). This is how HTTP.SYS looks up certificates, so you'll need this value. Now, from a command prompt running on the machine where the service is deployed, here's how you register the certificate with HTTP.SYS:

HTTPCFG add ssl -i 0.0.0.0:4242 31883a61892d8c...

Figure 1 Certificate Thumbprint

Figure 1** Certificate Thumbprint **

The first number you see is an IP address of 0.0.0.0, which represents all IP addresses that the machine can potentially have. If you're binding to a particular IP address you should use that value instead. Next is the port number on which the service will listen. And last is the thumbprint (you'll need to remove the spaces between the bytes if you copy this from the certificate viewer). I've only shown the first part of the hash for brevity, as it is 20 bytes long.

Winding Up

This is only the first of many pieces that I intend to write about security in Windows Communication Foundation. Here I introduced the security features and illustrated some of the basic choices you'll need to make when deciding how to secure services that you write. As you've seen, Windows Communication Foundation provides message confidentiality, integrity, and authentication over many different bindings, with the vast majority of the bindings being secured by default. The tips I've presented here on tweaking your bindings will help you get the most out of these features. In the future I'll explore other areas of Windows Communication Foundation security, including claims-based authorization and other fun topics. Stay tuned!

Send your questions and comments for Keith to  briefs@microsoft.com.

Keith Brown is a cofounder of Pluralsight, a premier Microsoft .NET training provider. Keith is the author of Pluralsight's Applied .NET Security course, as well as several books, including The .NET Developer's Guide to Windows Security, which is available both in print and on the Web.