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.