WIF claims are per definition safe from tampering, as they are signed, and you do use SSL, don’t you? However, there might be times when you don’t want even the end user to be able to read the contents of your claims. This might be because you use claims to transport some semi-secret information, some top-secret information, or information you just don’t want the user to know you use as a means of controlling his access to content.
The information on how to encrypt your claims is available, however, the information is a bit scattered. Some information may be found here:
It was putting it all together that was the challenge for me, anyway. I have rolled my own STS, and following the code you get if you select “Add STS reference” in Visual Studio, and then “Create a new STS project in the current solution”, we set the encryption like this:
public class MySecurityTokenService : SecurityTokenService
public MySecurityTokenService(SecurityTokenServiceConfiguration configuration)
protected override Scope GetScope( IClaimsPrincipal principal, RequestSecurityToken request )
ValidateAppliesTo( request.AppliesTo );
Scope scope = new Scope( request.AppliesTo.Uri.OriginalString, SecurityTokenServiceConfiguration.SigningCredentials );
string encryptingCertificateName = WebConfigurationManager.AppSettings[ "EncryptingCertificateName" ];
if ( !string.IsNullOrEmpty( encryptingCertificateName ) )
// Important note on setting the encrypting credentials.
// In a production deployment, you would need to select a certificate that is specific to the RP that is requesting the token.
// You can examine the 'request' to obtain information to determine the certificate to use.
scope.EncryptingCredentials = new X509EncryptingCredentials( CertificateUtil.GetCertificate( StoreName.My, StoreLocation.LocalMachine, encryptingCertificateName ) );
// If there is no encryption certificate specified, the STS will not perform encryption.
// This will succeed for tokens that are created without keys (BearerTokens) or asymmetric keys.
scope.TokenEncryptionRequired = false;
// Set the ReplyTo address for the WS-Federation passive protocol (wreply). This is the address to which responses will be directed.
// In this template, we have chosen to set this to the AppliesToAddress.
scope.ReplyToAddress = scope.AppliesToAddress;
The key is setting the
TokenEncryptionRequired and the
EncryptionCredentials on the scope.
Note also the comment in the template code, on using different certificates per RP in production code. You don’t want anyone but the RP you send the claims to decrypting the claims.
You would normally put this certificate in the “Other people” (aka “AddressBook”) certificate store, and you don’t need the private key for this certificate on the STS server(s).
Then, on the relying party (RP), you have to tell WIF where to find the certificate to use for decrypting the claims. The RP needs to have the private key of the certificate, to be able to decrypt the claims encrypted with its public key. It makes sense to put it in the “Personal” (aka “My”) certificate store.
This is done purely in configuration, in the
microsoft.IdentityModel/service section of Web.config. Just insert an element like this:
The rest of you WIF config goes here...
findValue="<thumbprint of the certificate used for encryption>"
Then you get the following in your claims set, instead of plain-text claims:
<xenc:EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<X509IssuerName>CN=MyCA, OU=MyOrg, O=MyComp, S=MyPlace, C=MyCountry</X509IssuerName>
<X509SerialNumber>***SERIAL NUMBER OF CERTIFICATE***</X509SerialNumber>
That should be it. Now your claims aren’t available for anyone to look at.