What User Identity does IIS use to run code like ISAPI and CGI, Part 2

I seem to have forgotten to describe how the following aspect of IIS functions in the prior post because I was concentrated on clarifying something else (that your Windows logon is NOT the same as logon via IIS). Thus, I got the following followup:


I am confused with your explanation in the 3 paragraph from bottom.

I thought that the configured Authentication has bearing only only whether the user is authenticated and permitted to access the resources (provided his identity has appropriate authorizations).
The identity under which the ISAPI DLL would run would be governed by the process identity of INETINFO.exe or W3wp.exe. This inturn is determined by the App pool account.

Pls. correct me if my understanding is incorrect.



Yes, you are describing one of many common misunderstanding about the user identity IIS uses to executes requests and run code like ISAPI and CGI.

Overall, the desired IIS behavior is to run user applications as the authenticated user identity, whatever it is.

Authentication controls the protocols that IIS will use to negotiate user identity with the client. At the end of Authentication, IIS expects to either reject with a 401 because the client failed to provide sufficient/correct user identification, or IIS will have a NT User Token that represents the user principle.

Then, IIS will use this NT User Token to perform all Authorization (access checks) against the requested resource.

Since anonymous authentication does not negotiate any user principle, it means that this authentication process MUST use some other pre-determined username/password. This is why IIS creates the IUSR_machine account and why you want to keep the username/password in sync within the metabase. If this username/password is incorrect, IIS will be unable to allow anonymous access because it cannot login the user identity to get a NT User Token to process the request, and it will return a 401.1.

After Authentication and Authorization finishes, IIS has two NT user tokens with which it can choose to execute this request with:

  1. The NT User Token obtained through the Authentication process
  2. The Process Identity

By design, IIS executes code in the following way:

  1. For ISAPI Filter DLL, the code is executed using the process identity. IIS will not impersonate user identity prior to invoking its entrypoints. This makes a lot of sense because impersonation is expensive and ISAPI Filter runs during request processing itself - and IIS certainly does not impersonate unnecessarily.
  2. For ISAPI Extension DLL, the code is executed by impersonating the NT User Token obtained through Authentication. This allows ISAPI applications like ASP and ASP.Net to offer security checks based on the remote user's identity - a powerful integration feature.
  3. For CGI EXE, it depends on the value of the "CreateProcessAsUser" metabase property applicable to the URL. It defaults to TRUE and means to create the CGI process using the NT User Token obtained through Authentication. If FALSE, then the Process Identity is used instead.

Now, how the ISAPI and CGI chooses to execute code afterwards, that behavior is completely arbitrary and outside of IIS control. For example:

  1. ASP chooses to keep the impersonated identity and use it to execute the page and access resources
  2. ASP.Net allows configuration via the <identity> element. You can tell ASP.Net to keep the impersonated identity, strip it off and use the Process Identity, or impersonate a totally new username/password to execute code

Finally, ISAPIs like ASP and ASP.Net are application frameworks that allow arbitrary user code to run, so some of that user code CAN change the impersonation token of a thread (which subsequently changes the identity used to execute other code on that thread [until the thread token is reset, of course - but this is no longer documented nor reliable behavior]). Thus, it is also possible for some COM components instantiated in your ASP page or global.asa file, or Managed code classes calling RevertToSelf() or otherwise stripping/resetting the impersonation token, to change the effective user identity that executes code on the server.


Comments (35)

  1. David Wang says:

    What User Identity does IIS use to run code like ISAPI and CGI.

  2. David Wang says:

    One of the most common questions asked about IIS on the newsgroups as well as Microsoft Product Support…

  3. David Wang says:

    One of the most common questions asked about IIS on the newsgroups as well as Microsoft Product Support…

  4. David Wang says:

    I usually want&amp;nbsp;a high ratio of answer content&amp;nbsp;to question content, but the following question…

  5. Great info.  I do have a question for you.  If the IUSR_Machinename account is out of sync with the OS how do you correct this issue?

    Thanks in advance and thanks for the article!


  6. David.Wang says:

    Martin – There are many ways to synchronize. Here is one approach:

    1. Set the NT User account to a known password:


    2. Change Anonymous username/password in IIS to match the known username/password:



  7. Thanks for your answer to my question and I did do what you sugested.  This is how I know the password is out of sync.

    What I really want to know is how do I tell IIS to get the new password for the IUSR accnt or how do I manually reset it.  

    I’m a programmer and create a number of sites on several different servers.  Usally when a site is created IIS populates the ananymous access option with the ISUR accnt and correct password. In the case of this server it doesn’t.

    For the sanity of myself and other programmers in the company it would be benifitial if all the servers behaved consistently.

    Thanks again.


  8. David.Wang says:

    Martin – You cannot tell IIS to get the new password because it does not "own" the account. IIS can create the account when it doesn’t exist, so it can obviously set the password and synchronize at that point. This is how it usually works and no one has to do anything. However, if you subsequently change things, either by changing the password for the user account or if you configure a different anonymous user, you are obviously responsible for synchronizing it at all places.

    At this point, it sounds like you either have:

    1. W3SVC/AnonymousUser* is out of sync with the NT user account on that server

    2. Your creation of websites is explicitly setting AnonymousUser* that is out of sync with that server

    For #1, my previous comment should allow you to address your issue. For #2, you need to fix your website creation code to use the right password.

    Personally, I suggest #1, where your site creation code does *not* set AnonymousUser* and let the local inheritance automatically work out… unless for some reason you need to explicitly control the anonymous user account… in which case you must do the work of #2.


  9. Laxmikanth says:

    I really appreciate the time you take out to write out such detailed articles. They are definitely a great read.

    Are there any subtle differences in Worker Process’s impersonation of ASP ISAPI extension when it is configured to run as a predefined Network Service Identity and run as a Windows Network User Account?

    If your point 2 (describing the way IIS is designed to execute ISAPI extensions) is true, an ASP page executed as a result a user’s request should give identical results irrespective of the associated AppPool identity. However, my observation is that this is not entirely true for a situation with AppPool configured to use Network Service identity.


    OS – Windows Server 2003 SP1 – member of Active Directory domain

    IIS – 6.0

    Windows SharePoint Services 2.0 SP2 installed and configured

    We have an ASP application running under a user defined application pool. The AppPool is configured to run under a Windows Network user identity (this identity is not an administrator on this computer). An ASP page in this application (has some bad code) uses Windows Scripting host to make calls to a SharePoint’s STADM.EXE. This particular EXE requires that the calling user be a local administrator of the current system. This page (and the call to STSADM.EXE) executes without an error when the requestor is a local administrator. This fits into your explanation of the Worker Process impersonating the calling user to execute the ASP page under the Authenticated identity.

    However, the same page requested by the same user fails to execute when the AppPool is configured for Network Service Identity.

    Could you help me understand this?

    Btw, you look good in the white turtle….

  10. David.Wang says:

    Laxmikanth – Actually, your question illustrates the detailed understanding one must have to distinguish when code is run "by ASP" or "by something else".

    The difference here is NOT in the user impersonation done by the Worker Process but rather how CreateProcess() and the code it invokes interprets it.

    1. The Run() method of the Windows Scripting Host "WScript.Shell" object uses CreateProcess() to launch the command (you can easily figure this out by attaching a debugger with public symbols, setting breakpoints on CreateProcess*, and watching what gets hit)

    2. Here is documentation for CreateProcess() http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createprocess.asp

    3. Note that the documentation states:

    If the calling process is impersonating another user, the new process uses the token for the calling process, not the impersonation token. To run the new process in the security context of the user represented by the impersonation token, use the CreateProcessAsUser or CreateProcessWithLogonW function.

    Thus, it is the Process Identity, not Impersonated Identity, which is used to run the STSADM.EXE. Thus, when you configure the AppPool as Network Service, it should not work, regardless of impersonated identity.

    As for why it "worked" when the Process Identity is not a local administrator – I am not sure, but it is easy to attach a debugger and use lsaexts.dumpToken() to figure out the difference.

    In any case, the difference is not in how IIS performs the Impersonation (there’s only one way to do it) but rather in how invoked code use and interpret the Impersonation.


  11. Laxmikanth says:


    Thanks for your quick and prompt respone.

    I believe I do not understand your response completely, but I would take time to read through it and discuss with my friends.

    I shall write back to you in case of further questions.

    Once again, thanks a ton for your prompt response.

  12. David Wang says:

    Sigh… security continues to befuddle users… because why would you change the Service User Account&amp;nbsp;from…

  13. David Wang says:

    I finally have enough blog entries about various portions of IIS6 request processing that I can stitch…

  14. David Wang says:

    Every once in a while, I see users asking about how to automate Office applications on the server, either…

  15. David – you seem like the right resource for this question. I have a client who has created their own Web site. This was built over time from simple HTML pages and eventually grew into ASP pages and the like. They use a database for authentication of users and save the user token in a cookie. I don’t believe this to be relevant except that I want you to understand they do NOT use NT Authentication for users and will not in the forseeable future.

    There is one page in their site that programatically creates, modifies, or deletes files on the site. Currently, the IUSR_account has fill rights to the site directory (create, modify, …). I would like to set the IUSR_account rights to something lower and have this single page run as a different user.

    How can this be done?

  16. AnilR says:

    David, great article thanks. That cleared up my somewhat hazy view of the subject.

    So now the obvious question: I want to use Windows Authentication, and I want my ASP page (not ASP.Net) to know who the user is. However, I don’t want to execute code using a users account; I want to use the application pool account, how?


  17. David.Wang says:

    Michael – I suggest configuring a dedicated user account for use as Anonymous user account for that specific page, and give this user account full rights on the necessary directories/files to create/modify/delete files.

    Now, you may choose to limit the privileges of this particular user (user privileges are different from account rights to resources) as well as configure which part of the URL namespace has this anonymous user applicable. Of course, this approach has other security ramifications (such as repudiation), but that is really a flaw within this custom authorization scheme.


  18. David.Wang says:

    AnilR – since ASP runs all code as the impersonated user and has no functionality to configure nor change that user identity, what you want to do is impossible with just  ASP.

    You can use or create 3rd party COM component DLLs that call RevertToSelf() on the thread, and then you invoke the COM component within the ASP page to change the user identity executing that ASP page from that point forward. Just remember that every time the ASP page is executed, IIS re-impersonates.


  19. Chris says:


    The inforamtion you have provided here has been very helpful however I am still getting a cgi error. I created an anonymous user account specifically for the purpose of running .pl files on the local box as you suggest and given the create, modify, delete rights  to the appropriate folder/files yet I still get the following cgi error "The specified CGI application misbehaved by not returning a complete set of HTTP headers." I also changed the anonymous account specified at the site level under "Authentication and access control" in IIS 6. What am I missing?

    Thank you,


  20. David.Wang says:

    Chris – the 502 error ("The specified CGI application misbehaved by not returning a complete set of HTTP headers") has to do with the response generated by the .pl script. It usually has nothing to do with the topic of this blog entry – user identity – unless the script blows up when running as the wrong user identity and generates a non-HTTP response — which would then show up as a 502.

    The most important thing to diagnosing a 502 is to determine what the CGI script sent as the response. This can be done either by:

    1. running the .pl script from the commandline as the appropriate user account and with the proper CGI environment variables set.

    2. renaming the .pl to have a nph- prefix and make a request with a raw HTTP Client like WFetch to view the actual response generated by the .pl script as IIS runs it.

    #2 is the more realistic and my preferred verification method. It does require renaming a file and using a raw HTTP Client like WFetch from the IIS6 Resource Kit, but it is worth it because some CGI errors can only be debugged this way.


  21. Chris says:

    Thank you for your detailed response David. It is curious though that if I change the IUSR account back to the old domain IUSR which is running on an old NT4 box that I don’t get this error at all. It’s only when I change it to the local IUSR or the guest account I created that it throws this error. After much reading I thought it was related to the lock down of IUSR in IIS 6 where IUSR is denied Write access to Web content by default.

  22. David.Wang says:

    Chris – NT4 was also insecure and allowed Everyone Full Control, so the fact that it "works" on it does not mean it was anywhere near secure enough to work on Windows Server 2003 and IIS6.

    I would not assume that the problem is related to the "lock down of IUSR in IIS6" unless I see evidence. Guessing based on what you have read, without concrete evidence, is ineffective troubleshooting.

    I suggest starting from what you do observe – a 502 response – and work backwards from there because everything is then based on fact. 502 tells you that executing the CGI did not generate a proper response. There is no way that I jump from there to assuming that something is wrong with the anonymous user account and start acting on that assumption. I would try to isolate that response and examine what is not "proper" about it before making further assessments.

    If the response does not conform to CGI specifications, which IIS6 now checks (while previous IIS versions did not check), then that indicates a problem with the .pl script that needs to be fixed. Remember, just because it worked on IIS4 does not mean it is correct.

    If the response looks like an error response because of insufficient privileges, then depending on the authentication protocol, that suggests a problem with remote authenticated account. If anonymous protocol was chosen, then it is the anonymous user account that you configured. Domain IUSR and local IUSR are two totally different accounts (and Guest is a totally different account with different lockdown) with different names and possibly passwords, so I would never assume they give the same behavior when used by your script.

    My guess is that the latter is happening for local IUSR/Guest and is probably "by-design" – because it sounds like the .pl script is designed to work with the old domain IUSR.

    It is always your responsibility to figure out the correct user and privileges required by your application. If you don’t know, then you need to learn how to figure it out.


  23. David.Wang says:

    It’s a 10K entry!


  24. Mark says:

    After getting pass the 403.1 error in running perl scripts, I’m now getting a 502 error. File Monitor was able to tell me the error was caused by the script not finding the perl56.dll file.  I’m not sure why, but the script is looking for the dll file in the site’s root folder. I can get around this problem by copy/paste the dll file to the root, but that’s obviously not the way to solve this. I was wondering if you have any suggestions?

  25. Tiago says:


    hope this does not fall out of context in the current blog, but given its importance here goes.

    While all the above is correct, there should be an important security awareness related to ASP.NET and the impersonated account with which the current request is being executed whether its anonymous/basic/IWA.

    While the whole request execution (inside the extension processing, not filter) is done through the impersonated account the Application_Start event is unfortunatelly executed under the process account (the account with which filters execute, not extensions) and that should also be noted as a security issue since ASP.NET web applications – AppDomains – at start time, lose their isolation at this precise time. Any web application can query the same data the other web applications query at that event. web applications should not involve authorized accesses inside this Application_Start event.

    There are several ways to circumvent this situation: using Session_Start (if using sessions), using an Application level auto-reset event used at some point inside the first http request processing and others …

  26. David.Wang says:

    Mark – Your question is not really related to IIS.

    IIS just loads the ISAPI DLL or executes the CGI EXE. Any additional dependencies is the responsibility of the ISAPI/CGI itself.

    For example, if it is a runtime DLL loading dependency, then it is really PERL not installed correctly – which I can only suggest to contact the Perl support groups for advice.


  27. David.Wang says:

    Tiago – thanks for the useful info.

    FYI: It really falls under the context of the specific ISAPI. IIS will run ISAPI and CGI as I describe above. What the ISAPI/CGI does in turn to execute its extensibility API… it is totally dependent on the ISAPI/CGI. There is no IIS configuration to affect this behavior.


  28. Anonymous Coward says:

    Can you further clarify the identity used when using an ISAPI extension such as PHP and you’re using the default Application Pool identity of "NETWORK SERVICE"? The article seems to imply it should be using the app pool id as it’s identity but it looks like its still using the IUSR id.

    When trying to call a PHP page anonymously (with anonymous access on for the website), I get the following from Authentication & Access Control Monitoring:


    I want to tie down file access and ACLS for the PHP installation to the Service not the IUSR!

  29. Anonymous Coward says:


    not the right log entries…

    To summarise.. looks like the verification of  the PHP DLL is done using the NETWORK SERVICE. This works because NTFS perms have been set, but  then subsequent access is using the IUSR id. GRR.

    Any help would be appreciated.

  30. John Ortega says:


    I’m working on an ASP website with IIS 6 and Windows Server 2003. Something weird is happening and you seem like the one to help.

    I get page cannot be displayed on any attempt to call a shell command from the asp page. I’ve set all (I*) users in with full permissions.

    The funny thing is that when I remote login it works fine.

    Could you help?



  31. Priti says:


    My .NET application uses word automation to create new documents. With Word Identity as ‘Interactive user’, my application works fine on the development machine.

    When I deploy it on the client server, it gives error saying the ‘Configured identity is incorrect’. How do I configure IIS to run for Interactive user?



  32. David.Wang says:

    Anonymous – For PHP ISAPI **EXTENSION**, what you observed is exactly correct and what you configured.

    IIS runs ISAPI Extension with the impersonated identity, which you’ve configured as IUSR for Anonymous authentication.

    IIS verifies PHP ISAPI DLL using process identity since it does the impersonation right before executing the ISAPI Extension DLL, while verification happens way earlier.

    There is no way for you to tie down PHP ISAPI access to just the process identity. It is not how IIS works.


  33. Andre Ames says:

    Hello David,

    I am Andre from the Netherlands. I just want to say that you helped me out wiht this great site.

    So, thank you.

    Best regards,


  34. Hi,

    i discovered, that using FastCGI, PHP run’s under the process identity.

    With fastcgi.impersonate = 1 in PHP.INI you can selectively switch back to the anonymous / authenticated user.

    I’m going to try this on one of my production Servers.

    @David: Thank you so much for this great blog. I learned so much from your postings!

  35. Kevin says:

    Does anyone know where I can find more literatures on how to configure impersonation account on IIS?  I read all explanation but needs a little example.  thanks

Skip to main content