1. 分析
1) 获取服务器的SPN
a) 通过SQLCheck.exe(需要到微软官网进行下载)
b) 通过setspn工具
2) 判断SPN是否正确,如果不正确则需要矫正SPN
a) 如果好的连接找不到任何SPN则会使用NLTM
b) 如果好的连接能找到自己组合生成的SPN,则使用Kerberos认证,
c) 如果不好的连接找不到自己组合的SPN则使用NLTM
d) 如果不好的连接找到了自己组合的SPN则连接失败
3) 查看连接使用的是那种认证方式
SELECT net_transport, auth_scheme
FROM sys.dm_exec_connections
WHERE session_id = @@SPID;
4) 检查客户端是否可以获得票据
klist get <SPN>
示例:
MSSQLSvc/<server_name>.domain.com:1433
如果获取失败,需要测试是不是只有SQL Server服务不能获取票据
• Klist get Host/dc.domain.com 在数据库服务器上执行
• Klist get Host/sqlserver.domain.com
2. Kerberos和NLTM详解
1) Kerberos
a) 认证流程:Trust-Third_party架构
Kerberos认证提供一种服务器和客户端相互认证的机制。Kerberos包含了三个关键组件:Key Distribution Center (KDC),客户端用户,和一个运行所需服务的服务器。KDC是域控制器的一部分,它执行两个任务:认证服务(AS)和票据许可服务(TGS)。当客户端用户登录到网络上时,它会向用户所在域的 AS 去请求一个“票据请求票据”(TGT)。然后,当客户端想要访问网络上的某个资源的话,它就出示以下东西:TGT,认证码,Server Principal Name(SPN);有了这些东西,客户端就可以从服务所在的域中的TGS获得session票据。使用这个session票据,客户端就可以和网络上的服务进行交流,该 服务会验证“认证码”然后创建一个访问令牌给客户端用户,接下来客户端就可以登录上该服务了。
b) Kerberos的要求:
• 客户端和服务器端一定要加入域,如果客户端和服务器端在不同的域的话,这两个域一定要被配置被互相信任。
• 注册SPN。SPN是服务器上所运行服务的唯一标示。每个使用Kerberos的服务都需要一个SPN,这样客户沪端才可以辨认这个服务。SPN是注册在AD上的机器账户或者是域用户账户下的。比如,如果SQL Server运行在Local System或Network Service账户下,那么SPN就需要注册在机器账户下。如果 SQL Server运行在域用户下,则SPN就需要注册在该域用户下。
• 这个顺便提一下。当一个服务运行在Local System或Network Service下的时候,我们称该服务运行在机器帐户下。因为,从AD的角度来看,每台机器的Local System或Network Service都代表了这条机器本身,而机器本身也是一种用户,叫做机器帐户。
2) NLTM
a) 认证流程::Challenge – Response 模式
在使用NTLM协议时,客户端发送用户名到服务器端;服务器生成一个challenge并发送给客户端;客户端使用用户的密码来加密这个challenge,然后发送response到服务器端。如果该账号是一个本机账号,那么服务器使用Security Account Manager来验证用户;如果账号是一个域账号,那么服务器把这 个response请求转送到域控制器(DC)上来让域控制器调用组安全策略来做用户认证,然后服务器就可以构建一个安全令牌并建立一个session。
b) NLTM的要求
要测试NTLM是否正常。可以使用以下命令:
"net view \\server", or "net view \\ipaddress"
3) Kerberos vs NLTM
a) 使用Kerberos来作为SQL Server的连接协议,至少是可以获得三种好处。
i) 安全性上的优势。NTLM在面对一些安全攻击的时候还是相对脆弱,比如它不能很好的防范中间人(man-in-the-middle)的攻击。一些使用Kerberos的关键优势,可以从这里找到。
ii) 有一些应用程序,包括微软的SCCM,SCOM等,是要求运行在Local System帐户下的。Local System账号会使得NTLM无法工作。这个时候我们就需要把Kerberos配置通才能使得应用程序可以成功登陆SQL Server。
iii) 在所谓的double-hop的应用场景下,我们需要使用委托的功能把客户端的身份信息传送到最后端的SQL Server。此时只有Kerberos才能完成“委托”的重任。否则在最后端的SQL Server就会收到一个登陆失败的提示。
b) NTLM fallback
i) Windows使用一种被称为negotiate (SPNEGO)的算法来协商应该使用哪种认证方式。当连接SQL Server时,客户端驱动解析SQL Server的DNS名字然后组成它是以想要的SPN,讲这个SPN交给SPNEGO,让SPNEGO到KDC上去查找是否有合适的SPN,并以此来决定使用Keberos或NTLM。从 Windows Server 2003开始,Kerberos都是默认的认证方式。但是当Kerberos失败的时候,可能会去尝试使用NTLM,这就被称为fallback。为什么要说“可能”呢?
ii) 因为当网络上有没有SPN注册时候,这个时候Fallback才会发生。当网络上有SPN注册,但是如果注册SPN的账号不是SQL Server服务账号(也就是说AD中SPN确实存在,但是注册在了错误的账号下),这个时候,无论是否存在一个被注册在正确的SQL Server服务账号下的SPN,Kerberos都会失败, 而这种失败是不会fallback到NTLM上的。也就是说这种情况下,无论NTLM是不是可以用,认证都会直接失败。
3. SPN详解
1) SPN的格式
a) Named instance
i) 语法
MSSQLSvc/<FQDN>:[<port> | <instancename>]
• MSSQLSvc is the service that is being registered.
• <FQDN> is the fully qualified domain name of the server. 还有一种就是SQL Server的计算机的netbios名字,俗称短名。
• <port> is the TCP port number.
• <instancename> is the name of the SQL Server instance.
ii) 示例
MSSQLSvc/<server_name>:<INSTANCE_NAME>
MSSQLSvc/<server_name>:1433
MSSQLSvc/<server_name>.domain.com:<INSTANCE_NAME>
MSSQLSvc/<server_name>.domain.com:1433
b) Default instance
i) 语法
MSSQLSvc/<FQDN>:<port> | MSSQLSvc/<FQDN>
• MSSQLSvc is the service that is being registered.
• <FQDN> is the fully qualified domain name of the server.还有一种就是SQL Server的计算机的netbios名字,俗称短名。
• <port> is the TCP port number.
ii) 示例
MSSQLSvc/<server_name>
MSSQLSvc/<server_name>:1433
MSSQLSvc/<server_name>.domain.com
MSSQLSvc/<server_name>.domain.com:1433
2) SPN的注册
a) 自动注册SPN
i) 说明
• 当SQL Server数据库引擎的实例启动时,SQL Server会尝试为SQL Server服务注册SPN。当实例停止时,SQL Server会尝试注销SPN。对于TCP/IP连接,SPN的注册格式为MSSQLSvc/<FQDN>:<tcpport>。命名实例和默认实例都注册为MSSQLSvc,依赖<tcpport>值来区分实例。
• 给SQL Server的服务启动账号注册和修改SPN的权限,需要执行如下:
打开Active Directory Users and Computers,选择View > Advanced.在Computers下,找到对应的SQL Server服务器右击选择属性,然后在安全页面选择高级,如果SQL Server的启动账号没有在list中,则需要添加账户并授予读和写SPN的权限
• Read servicePrincipalName
• Write servicePrincipalName
ii) 错误日志中自动注册SPN成功的信息
• The SQL Server Network Interface library successfully registered the Service Principal Name (SPN) [ MSSQLSvc/node2.mssqlwiki.com ] for the SQL Server service.
• The SQL Server Network Interface library successfully registered the Service Principal Name (SPN) [ MSSQLSvc/node2.mssqlwiki.com:1433 ] for the SQL Server service.
iii) 错误日志信息中自动注册SPN的相关日志条目(命令实例)
• SQL Server is attempting to register a Service Principal Name (SPN) for the SQL Server service. Kerberos authentication will not be possible until a SPN is registered for the SQL Server service. This is an informational message. No user action is required.
• The SQL Server Network Interface library could not register the Service Principal Name (SPN) [ MSSQLSvc/<server_name>.domain.com:INSTANCE_NAME ] for the SQL Server service. Windows return code: 0x200b, state: 15. Failure to register a SPN might cause integrated authentication to use NTLM instead of Kerberos. This is an informational message. Further action is only required if Kerberos authentication is required by authentication policies and if the SPN has not been manually registered.
• The SQL Server Network Interface library could not register the Service Principal Name (SPN) [ MSSQLSvc/<server_name>.domain.com:1433 ] for the SQL Server service. Windows return code: 0x200b, state: 15. Failure to register a SPN might cause integrated authentication to use NTLM instead of Kerberos. This is an informational message. Further action is only required if Kerberos authentication is required by authentication policies and if the SPN has not been manually registered.
iv) 尝试通过预设的虚拟帐号与 local admin 进行,都是会出现注册失败的情况,如下列的信息。
• 2024-02-07 14:16:37.49 Server The service account is 'NT SERVICE\MSSQLSERVER'. This is an informational message; no user action is required.
2024-02-07 14:16:38.30 Server The SQL Server Network Interface library could not register the Service Principal Name (SPN) [ MSSQLSvc/Cary-SQL2019 ] for the SQL Server service. Windows return code: 0xffffffff, state: 63. Failure to register a SPN might cause integrated authentication to use NTLM instead of Kerberos. This is an informational message. Further action is only required if Kerberos authentication is required by authentication policies and if the SPN has not been manually registered.
• 2024-01-31 14:43:17.93 Server The service account is 'CARY-SQL2019\Administrator'. This is an informational message; no user action is required.
2024-01-31 14:43:28.65 Server The SQL Server Network Interface library could not register the Service Principal Name (SPN) [ MSSQLSvc/Cary-SQL2019 ] for the SQL Server service. Windows return code: 0xffffffff, state: 53. Failure to register a SPN might cause integrated authentication to use NTLM instead of Kerberos. This is an informational message. Further action is only required if Kerberos authentication is required by authentication policies and if the SPN has not been manually registered.
b) 手动注册SPN
通过setspn命令
4. SPN的常用操作
1) 查看SPN
a) 基于账号查看SPN
i) 如果SQL Server服务使用非域账号启动(例如NT service或者local network等)
setspn -L <server_name>
ii) SQL Server服务器使用域账号启动
setspn –L domain\<startup_account>
b) 基于SPN来查找账号
setspn -F -Q MSSQLSvc/<FQDN>:<Port>
2) 查看重复的SPN
setspn -X
3) 添加删除来纠正SPN
a) 需要权限
Domain Admins, Enterprise Admins, or you must have been delegated the appropriate authority.
b) 删除SPN
i) 默认实例
setspn -D MSSQLSvc/<server_name> domain\<startup_account>
setspn -D MSSQLSvc/<server_name>.domain.com domain\<startup_account>
ii) 命令实例
setspn -D MSSQLSvc/<server_name>:INSTANCE_NAME domain\<startup_account>
setspn -D MSSQLSvc/<server_name>.domain.com:INSTANCE_NAME domain\<startup_account>
c) 添加SPN
i) 默认实例
setspn -S MSSQLSvc/<server_name> domain\<startup_account>
setspn -S MSSQLSvc/<server_name>.domain.com domain\<startup_account>
ii) 命名实例
setspn -S MSSQLSvc/<server_name>:INSTANCE_NAME domain\<startup_account>
setspn -S MSSQLSvc/<server_name>.domain.com:INSTANCE_NAME domain\<startup_account>
d) 执行klist purge
5. 注意事项:
1) 通过'NT SERVICE\MSSQLSERVER'或者本地的账号作为数据库的启动账号的时候会导致SPN自动注册失败,只有使用域账号并且域账号有读取servicePrincipalName和写入servicePrincipalName的权限才能成功注册SPN
2) 执行操作的账号必须有这个权限Validated write to service principle name
3) 在修改了机器的名字之后需要手工进行spn的校正
4) 如果修改了数据库服务的启动账号,也需要手工矫正SPN
5) 使用shared memory的连接只会使用NTLM,只有使用TCP/IP和named pipes的连接才有可能使用Kerberos,在SQL Server服务器上连接数据库,会优先使用shared memory方式