Don’t Impersonate If You Don’t Have To


Previously, I claimed that impersonation wasn’t dangerous – to the impersonator – this is NOT true for the one being impersonated if it’s a high level account – it’s actually a fairly hazardous thing to be doing, since a lot of people make mistakes doing it, and either forget to check for failure and do things anyway, or forget to drop impersonation when they’re done. The thing is that if you _don’t_ impersonate, you’ll create opportunities for luring attacks – oh, joy.

Then we start getting into multiple hop impersonation, when implies either passing plain-text credentials around, or enabling delegation. Unconstrained delegation, which was the only kind you could get in Windows 2000, is incredibly dangerous – basically allows anyone with admin rights on that system to do anything as any user who either normally logs on, or can be induced to log on. Most good network admins just aren’t going to let you do that, which puts you back in the plain text password business, and that’s not a business I’d like to be in. With Windows Server 2003, there’s constrained delegation, and that’s a lot safer, but it is still tough to get set up, and you need a domain admin to help you out at setup time.

The other situation that causes problems is that you have a middle tier server that can grab resources from some other server, and it needs to do so using one account – maybe you don’t need the overhead of zillions of logons. For example, DCOM objects can run as Interactive (not advisable), a specific user, or the caller. Running as the caller is best for security (least common shared mechanism), but it is horrible for perf – lots of overhead there.

What you can do, assuming you’re dealing with a Win2k3 server as a minimum platform, is to use the Authz APIs – mostly, these are there to allow you to do completely custom authz, but it also has some neat implications if you don’t want to go to that much trouble. If you can get an identification token, you can then call AuthzInitializeContextFromToken, and if you can only get the SID for the user, you can call AuthzInitializeContextFromSid, though this has some drawbacks. If you can then fetch the security descriptor for the object (or objects) you’d like to check, you can call AuthzAccessCheck. This is a LOT lighter weight process than having to perform an entire logon. You can also dink around with the context, add SIDs, or even add restricting SIDs. There are still some things to look out for – one of the issues to deal with is groups in the DACL that only make sense when evaluated locally. Grabbing a security descriptor from another system, and then evaluating it locally can lead to problems – for example, if an object is stored on a domain controller, and there is an ACE for Administrators, then that’s the Administrators group for the _domain_, not your system. When creating ACLs for objects where the check should be performed on some other system than the system keeping the objects, be careful not to allow groups that can only be evaluated locally.

Now that we have Authz APIs, and it’s getting to be a reasonable assumption that the minimum platform should be Win2k3, this whole can of worms is a lot more tractable. I think some future book needs a whole chapter on the ins and outs of the impersonation and delegation problem.

 


Comments (3)

  1. alikl says:

    David!,

    Great post on high level merits/demerits of passing identity over physical tiers.

    I am posting short series on the same subject on my blog – so far covered impersonation and finished writing about Delegation and Protocol transition – will post tonight. I do not pretend to be a good book chapter but small hub for technical how-to’s and further reading – it is all based on MSDN and patterns&practices stuff

    here is the link http://blogs.msdn.com/alikl/archive/2007/04/06/identity-flow-through-physical-tiers-impersonation.aspx

  2. Kris says:

    I have recently implemented Constrained Delegation for Web Services. We have a bunch of ASP.NET apps calling into these web services. Some are trivial web services and others are not, so we needed to pass the client context to the web services so that we know who exactly is accessing the service for audit purposes. I don’t need the Client context because I am using trusted auth scheme to the down level servers from the web services. But I do need the client identity to be passed securely. We have in the past passed the client identity as part of the web method call but we decided against this now and began to look for constrained delegation to solve this problem for us. It works but is non-trivial to set it up.

    Are there any alternatives to this (besides the trusted subsystem model)? Can Authz APIs help me in this scenario?

    [dcl] AuthZ might help, but you need to be careful how you pass the identity so it can’t be tampered with.

    Thanks.

  3. Well not everyone will agree with me but you have to after referring to David LeBlanc’s blog . Refer