Secure sessions and token caching

Aug 13, 2009 at 8:09 AM

Hi Michele,

Excellent whitepaper.  Lots of great info.  The authorization service was very creative and helpful.  I also appreciated what you had to say about token caching.  I've thought about this a bit myself, and blogged about a similar approach a while ago.  One thing I learned while spiking out that code was that the tokens require the service that receives them to asymmetrically decrypt them with every request.  This overhead is typically avoided on subsequent calls by establishing a symmetric session key that the client and service can use to talk securly using faster crypto.  Because the security tokens in the cache are asymmetric, what happens IINM, is this:

  1. The client sends an RST to the STS
  2. The STS issues the security token and returns it in the RSTR
  3. The client caches the token
  4. The client calls the service
  5. The service uses the asymmetric key in the security token to create a symmetric session key with the client
  6. The service fulfills the request
  7. The client closes the channel (if the channel is allowed to go out of scope)
  8. The service and client tear down their secure session
  9. The client creates a new channel to send another request to the service.  Before doing so, it gets the security token out of the cache, avoiding another trip to the STS
  10. Again, the service has to asymmetrically decrypt the security token and establish a symmetric session key with the client
  11. Again, the channel is closed on the client side (if it goes out of scope) and the two parties tear down their session that they only used for one call

(This might not be exactly right, but I think it is mostly right.)

So my questions are these:

  1. From what you (or anyone on the list) knows, am I right that the session is set up and torn down only to be used for the one call?
  2. Did you think about this and do you have any suggestions on how to avoid this limited use?

If I am right, I have two thoughts:

  1. Don't create the session at all

    I know that the WSFederationHttpBinding has secure sessions turned on and doesn't allow them to be turned off, forcing you to create a custom binding w/ secure sessions turned off to avoid the establishment of this needless symmetric key.  IIRC, Geneva Framework (or server) includes (or will include) a federation binding w/ secure sessions turned off.

  2. Hang on to the channel object.  Only by reusing this object can you use the symmetric session key multiple times.

Thoughts?

--

Regards,

Travis Spencer

Coordinator
Aug 14, 2009 at 9:38 PM

Hi Travis,

Hey, nice to hear from you, I have seen your name many a time on the forums answering questions!

In most cases the proxy should be cached for the lifetime of the client application, with the exception that of course if the session times out they will have to create the proxy again as well. I have a proxy generator at wcfproxygenerator.codeplex.com that can handle this.

Your observation is correct if people don't cache their proxy, but they should really cache the proxy otherwise things get very expensive at the client as well.

A session is a waste of effort if the proxy is not cached, correct. This would be more of an issue with server-server calls, for example from ASP.NET to a federated service, or from web service to services behind the firewall.

-Michele

 

Aug 16, 2009 at 7:41 AM

Hi Michele,

Thanks for the info. 

We aren't doing WPF programming ATM.  Right now, our focus is ASP.NET applications calling WCF services which in turn call many downstream WCF services. We did some tests of the caching of security tokens like I described on my blog and like you outlined in your paper.  We found that the asymmetric crypto being done to crack tokens on the service-side became prohibitively expensive during peak loads.  This point was of course better than without caching on the client-side.  To compensate, we were intending to utilize hardware accelleration; however, we found that the some of the WCF code didn't use the native crypto API, so hardware accelleration wouldn't help.  We've since been told that those problems have been fixed in a .NET 3.5 service pack.  (I don't know which one and haven't corroborated this.)

All this is to say that caching the tokens in some cases still isn't enough.  If you expect very large loads, this is a really hard problem to solve.

See ya in the forums ;-)

--

Regards,

Travis Spencer

Coordinator
Aug 16, 2009 at 7:09 PM

Hi Spencer,

Are you doing passive fed at the ASP.NET client and then using a delegated token from the ASP.NET tier to your back-end services?

What kind of performance numbers are you seeing? > 1 second per request?

A lot of people will hand roll channel pools when they need to cache proxies for server-server calls like this. Not ideal, but sometimes necessary. Of course in a federated scenario the other issue will be what does the channel cached? If the token is call or user specific, this doesn’t work well, if the token is more of a trusted subsystem token, the pool can be helpful. Unfortunately, if you need call or user specific claims to pass downstream and can’t afford the cost of decryption the only other option is to send the claims in a custom XML token, not as ClientCredentials since this requires a new factory, but as a custom header. Let the channel secure them. Kinda defeats the purpose of all the nice built-in federated goodness but c’est la vie!

-Michele

From: spencer205 [mailto:notifications@codeplex.com]
Sent: Saturday, August 15, 2009 11:41 PM
To: mlb@dasblonde.net
Subject: Re: Secure sessions and token caching [claimsbasedwpf:65426]

From: spencer205

Hi Michele,

Thanks for the info.

We aren't doing WPF programming ATM. Right now, our focus is ASP.NET applications calling WCF services which in turn call many downstream WCF services. We did some tests of the caching of security tokens like I described on my blog and like you outlined in your paper. We found that the asymmetric crypto being done to crack tokens on the service-side became prohibitively expensive during peak loads. This point was of course better than without caching on the client-side. To compensate, we were intending to utilize hardware accelleration; however, we found that the some of the WCF code didn't use the native crypto API, so hardware accelleration wouldn't help. We've since been told that those problems have been fixed in a .NET 3.5 service pack. (I don't know which one and haven't corroborated this.)

All this is to say that caching the tokens in some cases still isn't enough. If you expect very large loads, this is a really hard problem to solve.

See ya in the forums ;-)

--

Regards,

Travis Spencer

Read the full discussion online.

To add a post to this discussion, reply to this email (claimsbasedwpf@discussions.codeplex.com)

To start a new discussion for this project, email claimsbasedwpf@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

No virus found in this incoming message.
Checked by AVG - www.avg.com
Version: 8.5.392 / Virus Database: 270.13.56/2302 - Release Date: 08/15/09 18:10:00

Aug 18, 2009 at 6:49 AM

Hi Michele,

Are you doing passive fed at the ASP.NET client and then using a delegated token from the ASP.NET tier to your back-end services?

Yes. Because of the perf hit, however, we may only do ActAs tokens where the extra security is needed to offset above average risk. In other cases, the realm will encompass the Web front-end and the back-end services. I don't like the idea of sharing the private keys among these different applications, but, you're right, such is life.

What kind of performance numbers are you seeing? > 1 second per request?

I don't have the exact numbers. We did this test over a year ago. I tried to dig up the results today, but couldn't track 'em down. If I can find them (and get authorization to do so), I'll post 'em. I'm sure it was not sub-second; I think it was much worse than that.

A lot of people will hand roll channel pools when they need to cache proxies for server-server calls like this. Not ideal, but sometimes necessary. Of course in a federated scenario the other issue will be what does the channel cached? If the token is call or user specific, this doesn’t work well, if the token is more of a trusted subsystem token, the pool can be helpful.

Besides user data, we also have to consider tenant data as well -- we're do multi-tenant SaaS. So any sort of object pool in our case would been 3 dimensional: service (obviously), user, and tenant.  One way to avoid keying into the object pool using all three elements is to create new tenant-specific virtual apps in IIS -- each w/ their own app pool -- and map them onto the same bits.  Though this removed one dimension from the cache, the one-app-pool-per-tenant approach gets costly fast.

Unfortunately, if you need call or user specific claims to pass downstream and can’t afford the cost of decryption the only other option is to send the claims in a custom XML token, not as ClientCredentials since this requires a new factory, but as a custom header. Let the channel secure them. Kinda defeats the purpose of all the nice built-in federated goodness but c’est la vie!

That is a good thought.  Very practical.

--

Thanks Again,

Travis Spencer