Impersonation in .Net crashes when reading registr

2019-06-26 04:38发布

问题:

My app needs to impersonate a service account, which I do through a native-call to LogonUser. However, it appears that random components in the .Net library try to access registry keys the account doesn't have access to, causing a SecurityException to be thrown.

Specifically, when I load a LinkLabel, it crashes trying to determine the default hyperlink color in IE:

System.Security.SecurityException: Requested registry access is not allowed.
      at System.ThrowHelper.ThrowSecurityException(ExceptionResource resource)
      at Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable)
      at Microsoft.Win32.RegistryKey.OpenSubKey(String name)
      at System.Windows.Forms.LinkUtilities.GetIEColor(String name)
      at System.Windows.Forms.LinkUtilities.get_IELinkColor()
      at System.Windows.Forms.LinkLabel.get_LinkColor()
      at System.Windows.Forms.LinkLabel.OnPaint(PaintEventArgs e)
      at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
      at System.Windows.Forms.Control.WmPaint(Message& m)
      at System.Windows.Forms.Control.WndProc(Message& m)
      at System.Windows.Forms.Label.WndProc(Message& m)
      at System.Windows.Forms.LinkLabel.WndProc(Message& msg)
      at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
      at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
      at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
The Zone of the assembly that failed was:  MyComputer

No, setting the default color does not help.


I found this thread with the exact same problem, but I'm afraid I don't understand the solution:

Registry hives loaded with LoadUserProfile are stored under HKU, HKCU remains the interactive logon user's hive (loaded by winlogon.exe).

So if you need to get at the newly loaded hive you need to:
- set Regkey to Registry.Users
- Open the subkey using the string SID of the user account you are impersonating.

Does anyone know of any workarounds for this?

回答1:

The problem is you are impersonating too long and your code (indirectly through the .NET framework) is accessing more resources than you intended while impersonating. This exception seems to be caused by the fact your impersonation code is running on a GUI (STA) thread.

You can:

  1. Impersonate for a shorter period of time - only as long as you need to so call impersonate followed by undo as soon as you can. Even if one statement later you have to re-impersonate. This is the typical impersonation pattern.
  2. Move the impersonating code to a worker (MTA) thread and you should avoid this particular symptom. Now you have the problem of how to communicate with the impersonation code but it's not terrible.
  3. If you really want the whole process to run as the system account (as a least privilege sort of thing perhaps), the only supported solution I know of is to have HKEY_CURRENT_USER be something the system account can access. That's done by calling LoadUserProfile and then call CreateProcessAsUser; but that's a whole new architecture for you to spin a new process to handle the impersonation.


回答2:

What are you trying to do?

Why do you need to impersonate a service account? It doesn't seem like a good idea. I suggest you find a different way of solving whatever problem prompted you to do that.

If the users need access to some resource, grant access to that group of users.

Or create a COM server service to do the dirty work, and configure it to run as the service account but give your users launch permissions.

Really you mustn't do this. You are blowing a hole as big as a battleship in Windows security.



回答3:

It looks to me like the problem is the service account does not have access to HKEY_CURRENT_USER. You may be able to solve the problem by adding an ACE to your HKEY_CURRENT_USER hive granting read access to the service account.

This is also horribly insecure, by the way, if anything even worse. Use Tony Lee's number 1 option if you can get it to work.

Try it in Regedit before you go to the trouble of writing code to do it.



回答4:

For this specific problem, I just created a label (instead of a linklabel), made it blue and underlined, and set the Cursor to Cursors.Hand. Then it behaves exactly like a linklabel, except the link color doesn't change by the user's theme (oh well).

I then had other problems with permissions to save files; see my comments to @Tony's answer above for the solution.