使用 CredSpec 的经典 ASP/MSSQL 身份验证问题

Classic ASP/MSSQL Authentication Issue using CredSpec

我目前正在尝试对一些旧的(很快将被淘汰的)基础设施进行一些改进,以准备迁移到 .NET 核心。我们有一个小的反馈表,它使用 SQLOLEDB 连接字符串写入 SQL table。这些字符串与以明文定义的 username/password 配合使用时效果很好,但我希望放弃这种方法以支持集成身份验证。

我已经做了很多工作才能到达现在的位置:

  1. 基于安装了 ASP 功能的 IIS 构建了 docker 容器。
  2. 运行 Windows 主机上群中的容器 - 加入了我们的 AD 域。
  3. 设置 gMSA 以提供对数据库的域帐户访问权限。

目前,我已经 运行 完成了 Windows 容器指南中 MS 的 gMSA 中的所有步骤(https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/manage-serviceaccounts). The tests check out, I'm able to run all the tests in https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-containers/gmsa-troubleshooting#check-the-container 没有任何问题,但是当我尝试使用我的连接字符串,我在日志中收到错误显示:

2020-09-28 19:36:43 172.17.173.120 POST /Default.asp |42|80040e4d|Login_failed_for_user_'NT_AUTHORITY\ANONYMOUS_LOGON'.

这对我来说没有多大意义,因为应用程序池标识设置为网络并且测试在容器上检出。

现在我尝试了一些操作,例如编辑 web.config 以将模拟设置为 true/false,通过 Windows 进行身份验证,但我仍然有点难过。我已将主机设置为允许通过 Kerberos 委托任何服务。

我还尝试使用以下方式登录:

docker exec -it --user "NT AUTHORITY\NETWORK SERVICE" cb4 powershell

然后 运行:

$connectionString = 'Data Source=serverhostname.domain.local;database=databasename;Integrated Security = True;'
$sqlConnection = New-Object System.Data.SqlClient.SqlConnection $connectionString
$sqlConnection.Open()
$sqlConnection | select *

这导致数据库连接处于打开状态。

应用程序池是使用 NetworkService 身份设置的

Get-ItemProperty IIS:\AppPools\domain.co.uk\ -Name processModel

identityType           : NetworkService
userName               :
password               :
loadUserProfile        : False
setProfileEnvironment  : True
logonType              : LogonBatch
manualGroupMembership  : False
idleTimeout            : 00:20:00
idleTimeoutAction      : Terminate
maxProcesses           : 1
shutdownTimeLimit      : 00:01:30
startupTimeLimit       : 00:01:30
pingingEnabled         : True
pingInterval           : 00:00:30
pingResponseTime       : 00:01:30
logEventOnProcessModel : IdleTimeout
PSPath                 : WebAdministration::\413E8843BBEF\AppPools\domain.co.uk\
PSParentPath           : WebAdministration::\413E8843BBEF\AppPools
PSChildName            : domain.co.uk\
PSDrive                : IIS
PSProvider             : WebAdministration
Attributes             : {identityType, userName, password, loadUserProfile...}
ChildElements          : {}
ElementTagName         : processModel
Methods                :
Schema                 : Microsoft.IIs.PowerShell.Framework.ConfigurationElementSchema

如有任何建议,我们将不胜感激!

连接数据库需要注意以下几点

  1. 应用程序池的身份应该有一个域帐户。
  2. 域帐户具有读取或更改数据库的权限。
  3. IIS 服务器和 sql 服务器应在同一个 Intranet 中并使用同一个域。

更多细节可以参考这篇

好的,所以我弄明白了并将我的发现发布在 public 要点中:

https://gist.github.com/jimbo8098/48fa8d1cd05a61b35534aa107decb3e3

基本上,问题是当应用程序池标识设置为网络时,站点不是,它使用的似乎是 IUSR。鉴于此,我没有将 gMSA 帐户中继到 ASP 的脚本,因此我无法使用集成身份验证。解决方案是 运行:

Set-WebConfigurationProperty system.webServer/security/authentication/anonymousAuthentication -Name "userName" -Value ""; if ($?) {
Set-WebConfigurationProperty system.webServer/security/authentication/anonymousAuthentication -Name "password" -Value ""; if ($?) {
Set-WebConfigurationProperty system.webServer/security/authentication/anonymousAuthentication -Name "logonMethod" -Value 2;}}

这样做是将用户名和密码设置为空白,并将登录方法设置为网络。这是完美的,因为这意味着应用程序池和站点都使用了预期的帐户,即 gMSA 帐户。

我发现一个非常有用的方法是制作一个测试脚本:

<%
Set objNetwork = CreateObject("WScript.Network")
strNAME = objNetwork.computername
response.write("Value of strNAME variable: " & strNAME & "<br>")
response.write("Domain = " & objNetwork.UserDomain & "<br/>")
response.write("ComputerName = " & objNetwork.ComputerName & "<br/>")
response.write("UserName = " & objNetwork.UserName & "<br/>")
%>

在解决方案之前,这显示了 IUSR,这是我解决问题的重要线索。解决方案后,用户名读取 app$(其中 app 是 gMSA 的名称)以及预期的域。