ASP.NET模拟NT AUTHORITY\IUSR但禁用模拟.ASP.NET错误?

Mic*_*Liu 12 sql-server asp.net iis impersonation

我在"ASP.NET v4.0 Classic"应用程序池中的Windows 7/IIS 7.5上运行了一个ASP.NET 4.0应用程序,该应用程序池配置为作为网络服务运行.该应用程序具有Application_EndRequest连接到本地SQL Server实例的处理程序.SQL连接字符串指定Integrated Security=SSPI.Web.config文件并没有具备<identity impersonate="true" />.

当我浏览到时http://localhost/TestSite/,抛出以下异常:

System.Data.SqlClient.SqlException (0x80131904): Login failed for user 'NT AUTHORITY\IUSR'.
   ...
   at System.Data.SqlClient.SqlConnection.Open()
   at Global.Application_EndRequest(Object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

当我浏览到(在IIS中配置的默认文档)或任何其他.aspx页面时,不会抛出此异常http://localhost/TestSite/default.aspx; 在这些情况下,应用程序正确连接到SQL Server作为"NT AUTHORITY\NETWORK SERVICE",这是一个有效的登录.

为什么ASP.NET会在EndRequest中冒充"NT AUTHORITY\IUSR",即使模拟被禁用了?这是ASP.NET中的错误吗?

以下Global.asax.cs文件演示了此问题:

public class Global : HttpApplication
{
    public Global()
    {
        this.BeginRequest += delegate { Log("BeginRequest"); };
        this.PreRequestHandlerExecute += delegate { Log("PreRequestHandlerExecute"); };
        this.PostRequestHandlerExecute += delegate { Log("PostRequestHandlerExecute"); };
        this.EndRequest += delegate { Log("EndRequest"); };
    }

    protected void Application_EndRequest(Object sender, EventArgs e)
    {
        try
        {
            using (SqlConnection connection = new SqlConnection("Server=.;Integrated Security=SSPI"))
            {
                connection.Open();
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine(ex);
        }
    }

    private static void Log(string eventName)
    {
        HttpContext context = HttpContext.Current;
        Type impersonationContextType = typeof(HttpContext).Assembly.GetType("System.Web.ImpersonationContext", true);
        Trace.WriteLine(string.Format("ThreadId={0} {1} {2} Impersonating={3}",
            Thread.CurrentThread.ManagedThreadId,
            context.Request.Url,
            eventName,
            impersonationContextType.InvokeMember("CurrentThreadTokenExists", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetProperty, null, context, null)));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是跟踪输出:

ThreadId=3 http://localhost/TestSite/ BeginRequest Impersonating=False
ThreadId=3 http://localhost/TestSite/ PreRequestHandlerExecute Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx BeginRequest Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx PreRequestHandlerExecute Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx PostRequestHandlerExecute Impersonating=False
ThreadId=7 http://localhost/TestSite/default.aspx EndRequest Impersonating=False
ThreadId=7 http://localhost/TestSite/ PostRequestHandlerExecute Impersonating=True
ThreadId=7 http://localhost/TestSite/ EndRequest Impersonating=True
System.Data.SqlClient.SqlException (0x80131904): Login failed for user 'NT AUTHORITY\IUSR'.
   ...
   at System.Data.SqlClient.SqlConnection.Open()
   at Global.Application_EndRequest(Object sender, EventArgs e)
Run Code Online (Sandbox Code Playgroud)

请注意,对TestSite/(映射到DefaultHttpHandler)的请求似乎会产生嵌套请求TestSite/default.aspx(映射到ASP.default_aspx).ASP.NET完成处理后TestSite/default.aspx,它会在恢复处理请求时模拟"NT AUTHORITY\IUSR" TestSite/.

更新:我已将此问题提交给Microsoft Connect.

小智 25

最有可能的是,设置服务器,站点或应用程序的设置,以便"匿名身份验证"模式使页面请求作为IUSR用户处理.您的申请不要求假冒并不重要; IIS正在强迫它.(顺便说一下,"模仿"是Windows-land中用于假设其他用户凭据的通用术语.它不是特定于ASP.NET.)

一些背景知识:

出于安全原因,IIS允许您的服务器在不同的系统凭据下对"匿名"和"经过身份验证"的请求进行字段处理.

现在,在IIS 7.5中,如果您同时启用了匿名身份验证和表单身份验证(这是典型的),那么在您的网站用户通过表单登录之前,它会认为您的用户是"匿名的".在您的用户使用Forms Auth登录后,它会将您的用户视为"已通过身份验证".

我发现这种行为起初令人困惑,因为它是IIS 6.0的变化,它不知道Forms身份验证,并认为所有经过身份验证的用户都是匿名的!

如果需要,您可以更改匿名请求的身份.我的偏好(听起来也是你的)是他们在与我的网站的应用程序池相同的系统凭据下运行. 要使IIS执行此操作,请执行以下操作:

  1. 打开IIS管理器(inetmgr)
  2. 在"连接"面板中,向下钻取到站点的节点并选择它
  3. 在右侧面板的"IIS"组下,双击"身份验证"图标.
  4. 右键单击"匿名身​​份验证",然后从上下文菜单中选择"编辑...".
  5. 在弹出对话框中,选择"应用程序池标识"单选按钮.
  6. 单击确定.

第一步也让我困惑,因为我认为"应用程序池标识"意味着"应用程序池伪帐户"(IIS 7.5中的另一个新功能).当然,它的真正含义是"将应用程序池配置为运行的同一帐户,无论是什么."

如果您希望对该服务器上的所有网站,甚至只是特定站点下的单个应用程序执行此操作,您也可以在这些级别配置身份验证选项.只需在"连接"窗格中选择要配置的节点,然后重复步骤3-6.


Arc*_*rus 1

即使应用程序(可能)不使用模拟,为什么应用程序会尝试以“NT AUTHORITY\IUSR”身份登录?

如果你这样做

<identity impersonate="true"/>
Run Code Online (Sandbox Code Playgroud)

它将模拟登录用户

如果你这样做

<identity impersonate="true" userName="contoso\Jane" password="pass"/>
Run Code Online (Sandbox Code Playgroud)

它将模拟上面设置的用户。

但是,如果您根本不模拟并使用 Windows 身份验证,那么它使用默认系统帐户是有意义的。

我不知道为什么它第一次尝试作为 IUSR,然后在后续请求时自动切换到 NETWORK SERVICE。但我确实知道,当您从一台服务器跳转到另一台服务器时,不会使用应用程序池凭据。除非您如下所示设置模拟用户,否则 NETWORK SERVICE 是用于获取服务器外部资源的默认帐户。

    <connectionStrings>
        <add name="myConnectionString" connectionString="Data Source=MyServerName;Initial Catalog=MyDataBaseName;Integrated Security=True;"
          providerName="System.Data.SqlClient" />
      </connectionStrings>

<identity impersonate="true" userName="contoso\Jane" password="pass"/>
Run Code Online (Sandbox Code Playgroud)