| William's profile.Net ZoneBlogLists | Help |
|
January 24 Create SecurityContextTokens without X509 CertsSo I wanted to roll my own SecurityContextToken (SCT) service. Not because I want to reinvent the wheel, but because I did not want to have to use X509 certs and because I could not figure out how to issue SCTs using soap.tcp at the server. All the documentation addresses using IIS web service and ASP. First a word on SCTs as they can be a bit confusing. The goal is to authenticate to the server and get a SCT at both sides. The idea is you can only get a SCT if you authenticate at the server. The SCTs at both sides have a random 16 byte “secret” key that both sides can use to encrypt the rest of the session (using AES/Rijndael or other.) This is very similar to how SSL works. SCTs are a bit more flexible as you don’t have to encrypt all parts of the conversation, only those parts that need encryption, so it is an opt-in model. The interesting feature is that once the SCT is cached at the server side, you can send messages with only the SCT header in the message and the server can verify you already authenticated so you don’t need to keep sending a UsernameToken (UT). However, you *should encrypt and/or sign each message with the SCT, so that the server can verify your SCT “knows” the secret key. Otherwise anyone could construct a SCT using the same SCT.Identifier and can access your Web method, as only the Identifier string is sent in the header. At the server, the SCT also maps to an authenticated UsernameToken so that your methods can verify Role memberships and have access to the username, etc. In WSE, you can use the SecurityContextTokenServiceClient class to request a SCT from a URL. However this requires a server side X509 certificate. I wanted a secure solution that did not require a cert, but still used secure PKI to negotiate the SCT. This method resembles the built-in method, but requires only a standard RSA key pair as created with the RSACryptoServiceProvider class in the .Net framework. If you sign your assemblies with a strong name (SN), then you already have everything you need. The server private key needs to be secured as normal. The client’s public key is already in the assembly for ready access to create an RSA object from it. This does require that the client calling your web service actually is running your client assembly. If this is not the case, the client could also get the public key via some prior out-of-band method such as email, diskette, etc. You don’t want to allow the client to get the public key via a network call as a third party could do a Man-In-Middle attack by returning their own public key to your client. This is the reason server Certs where created in the first place to prove to the client that you got the correct key and not some other key by an attacker. As we "know" the server's public key already, we can avoid having to use Certs for this proof. If you did want to get Public key using a network call, you would need to return a Cert or have some prior security context setup between the you and the server. Anyway, here is the process: 1) Client creates public RSA object from public key of service. Now that client has its new SecurityContextToken, it should keep it for the rest of the session and *only use the SCT or a DerivedKeyToken (DKT) derived from the SCT. The UT is not needed or desired. The client should also *always encrypt or, at a minimum, sign all outgoing messages with the SCT or DKT. This is because the server can only verify you know the SCT shared key, if you sign or encrypt the message. We don’t need to keep attaching the UT in the Soap header because that would be redundant and just overhead. The SCT is already authenticated, so use that. We can also add consistency and security to all our web method if we always *require a SCT in the header. That way WSE automatically verifies the SCT, any hash, or decryption for us. We do, however, still need to assert in our methods (or in Policy) that a SCT was attached, and the body was signed (or encrypted as needed). As a rule, I would always require a body signature was attached. As noted, after we get our SCT, we can forget about any UTs. We don’t need to send them and should not (unless you have some specific need.) If you do need to attach a UsernameToken to a Soap header – always encrypt it using the SCT. The protocol summary is as follows: C->S C<-S Client (C) sends K1, Username, password, and C’s public key to Server (S). All elements are encrypted with S’s public key. Server creates SCT with generated sKey and returns K2, UT.ID, SCT.Identifier, SCT.Expires, KeyVerifier and Signature. K2 is encrypted with C’s public key. All elements are hashed and then signed using S’s private key. Client can then verify all elements have not been changed and message sent by S. Client generates sKey and SCT. That is about it. We now have a way to securely pass user credentials to the server and get a SCT in reply using soap.tcp and PKI. UsernameTokens are then out of the picture so we don’t have to worry about SendPlainText or SendHash stuff anymore. To keep this post ~short, I will show the implementation at Get SecurityContextToken C# Code . Also note, this implementation is updated at Updated Get SecurityContextToken in C#. Cheers! -- Comments (11)
Trackbacks (17)Weblogs that reference this entry
|
|
|