Security in WCF is all about credentials. Credentials are used for authentication; claims extracted from the credentials are used for authorization. If credential contains keys then these are used to provide integrity and confidentiality.
Credentials are supported both at transport level and message level. For message level credentials, WS-Security specification defines the mechanism to encapsulate security token (serialized representation of credentials) in a SOAP message.
When you use message security with WCF there are couple of interesting knobs which I am going to explain in this post. So let’s consider the following snippet as an example.
Setting establishSecurityContext="false" results in one shot message security. In this mode every message is secured independently -- algorithm suits determines what algorithm should be used to secure the message. By default WCF uses RSA-OAEP, which uses a symmetric key to encrypt the message and signature. This symmetric key is then wrapped/transported using the public key from the server certificate. All of this security stuff is contained in every SOAP message.
With one shot message security there are further two options:
o Not using derived keys
Above explanation was for case in which derived keys were turned off. Some of the other stacks (e.g IBM DataPower) don’t support derived keys yet so in those cases this needs to be turned off. By default wsHttpBinding uses the derived keys and there is no way to turn this off from the config file. You have to use a custom binding, if you need to turn off derived keys. See this for details. By default “derived keys” are turned off in case of basicHttpBinding.
o Using derived keys
With derived keys turned on, WCF derives two keys from the symmetric key and use one to sign the SOAP message and other to encrypt various parts of the SOAP message. It is considered bad practice to sign and encrypt data using the same key as certain attacks are more likely to succeed in this case so derived keys provide more resilient against such attacks and that’s why its enabled on wsHttpBinding as a default option.
Setting establishSecurityContext="true" results in a “Security Context Token” established between client and server. Once this token is created on both ends – all subsequent message exchanges will be secured using this context token. By default this token is issued with a 15 minute life time and need to be re-issued if required beyond 15 minutes. Again not using derived keys here means multiple messages (exchanged in 15 minutes life-span) will be secured using the same “Security Context Token” so security in this case will be more weaker than one shot security. So use of derived keys is more important in case of secure conversation.
Credential negotiation is a process of exchanging keys and authenticating communicating parties using some form of handshake. Now credential negotiate can be done at the transport level using something like SSL over HTTPS or can be done at SOAP level using TLSNego (SSL over SOAP).
Setting negotiateServiceCredential="false" means that service credentials should be made available to the client using some out-of-band mechanism. Here starts the complexity as WCF supports many different types of credentials and out-of-band availability mechanism is credential specific.
So in case of Certificate credentials, service certificate should be provided to all the clients prior to communication and clients should refer the service certificate in their security configuration.
<authentication certificateValidationMode="PeerOrChainTrust" />
In case of Kerberos credentials, setting negotiateServiceCredential="false" results in on-shot Kerberos or sometimes called Kerberos direct. For this mode to work the service must be running under machine SPN (NetworkService, LocalService accounts etc) and client must specify the SPN in the endpoint identity.
Setting negotiateServiceCredential="true" will results in credentials negotiation. Now as mentioned earlier actual negotiation depends on client and service credential type and could either be done at transport level or message level (using appropriate credential exchange protocols) depending on your security mode. Let’s take this example:
<message clientCredentialType="UserName" negotiateServiceCredential="true"/>
The above binding will result in UserNameForSslNegotiated credential type -- which uses UserName as client credential type and certificate as service credential and service credentials will be negotiated using SSL over SOAP aka TLSNEGO.