首先是问题:由于我对 SQL Server 2008 R2 (2016 年 3 月 3 日发布)应用了最新的补丁,这应该使我的服务器构建 10.50.6542 我无法再连接。这个补丁是为了提供对 TLS 1.2 的支持。
我得到的错误(尝试直接在服务器中使用客户端工具连接时)是
"A connection was succesfully established with the server, but then an error occurred during the pre-login handshake"
该服务器是 Windows Server 2012 R2 并且正在运行 NET Framework 4.6.1(一些帖子指向导致此问题的旧版本的 .NET 框架,但这不是我的情况)。
我尝试运行以下软件包以查看是否可以解决...
- SQL Server Native Client(x86 和 x64)
- Windows Server 2012 R2 和 Windows 8.1 中 .NET Framework 2.0 SP2 的修补程序汇总 3106993
- Windows 中 .NET Framework 4.0 的修补程序汇总 3106994
- .NET Framework 4.5.2、4.5.1 和 4.5 的修补程序汇总 3099845
...这些都不是必需的,也没有任何帮助...
有人经历过吗?有什么想法或建议吗?
谢谢!
一次更新 24 小时后 ,我检查了 SQL Server 错误日志,查找仅包含启动、5 次登录尝试失败和停止的条目。在该时间范围内的所有消息(总共 107 个条目)中,唯一包含错误之类的消息是
The SQL Server Network Interface library could not register the Service Principal Name (SPN) for the SQL Server service. Error: 0x2098, state: 15. Failure to register an SPN may cause integrated authentication to fall back to NTLM instead of Kerberos. This is an informational message. Further action is only required if Kerberos authentication is required by authentication policies.
不过,这条消息……甚至在我应用补丁之前就已经在服务器启动时报告了,所以我 100% 确信这是一条红鲱鱼。由于登录尝试失败,不会在 SQL Server 错误日志中插入任何日志。
另一个更新
根据我从这里的人那里得到的建议,我在服务器上下载并安装了最新版本的 SSMS(17.3)。当我这次尝试连接时,我得到了一个不同的错误,所以我似乎正在进一步移动,但我还没有到达那里。
因此,旧版本的 SSMS 确实以 .net 3.5 为目标,即使您有较新版本的 .net 框架,客户端连接也无法正常工作,现在的问题是为什么我仍然得到这个“没有进程位于管道的另一端”,即使大多数客户端组件已更新。
我调查过(并丢弃)的更多事情
- SQL Server 配置管理器中的“客户端协议”顺序似乎是正确的,因为 TCP/IP 位于顶部。这被认为是可能的麻烦原因,但在我的情况下,它都经过适当配置(显然)
尝试按照对 Microsoft SQL Server 的TLS 1.2 支持中的建议安装“Microsoft ODBC Driver for SQL Server”,但这也没有什么不同。安装后,报错信息是一样的
尝试在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2 中添加注册表项(也按照同一篇文章中的建议)。同样的错误……
最后!在阳光下尝试了 3 天后,我找到了问题的根本原因。
啊哈!那一刻,我和一群人聚在一起,试图理解为什么这个补丁在其他服务器上部署得很好,而在这个特定的服务器上却没有。
我们注意到一些不同的东西(除其他外......我们在一个组织整齐的记事本中列出)是这个 SQL Server 2008 R2 被配置为通过证书和 SQL Server 配置管理器上的一些设置进行传输中加密(也称为 SSL 加密) :
在 [Instance_Name] 的协议和属性(证书选项卡)上,我们选择了我们为加密通信而创建的证书。
在同一个窗口(标志选项卡)上,我们将数据库引擎的 ForceEncryption 选项设置为 Yes
所以我们开始思考......如果问题出在证书本身怎么办?然后我们继续删除加密配置(SQL Server Build 10.50.6542 的补丁仍然适用)并且连接开始工作,确认补丁加上我们的 SSL 配置的组合是疯狂的。
经过更多调查并通过消除过程,我们将问题缩小到我们正在使用的证书。该证书是使用 makecert (创建自签名证书)创建的,并且没有使用 -a 参数。这个参数告诉 makecert 使用什么哈希算法。如果未提供,makecert 将使用与 TLS 1.2 不兼容的默认 MD5 签名哈希算法。
同样在TLS 1.2 RFC上,您可以明确地看到……
因此,为了解决这个问题,解决方案是在 makecert 中添加 -a SHA256 参数(确保您使用的是 makecert 版本 6.3.9600.17298 而不是旧版本 5.1313790.0,因为那个不支持 SHA256 作为参数)。
我正在写所有这些,因为整个难题花了我 3 天的时间才弄清楚,我希望有一天有人会从中受益。如果只有微软会在描述补丁的文章中以大粗体字母表示不再支持 MD5 就好了!
感谢@Mr.Brownstone 和@sepupic 的帮助!
TLS 1.2 直到 .NET 4.6 才成为默认安全协议,甚至在 .NET 4.5 之前都不是受支持的选项,因此如果您使用的客户端以 .NET 运行时小于 4.5 为目标,它将无法默认使用 TLS 1.2 进行通信。
在您的特定场景中,客户端恰好是 SQL Server Management Studio。直到 2014 年(包括 2014 年)的管理工作室版本使用 .NET 3.5 SP1 作为目标运行时 - 不幸的是,这将阻止您按原样使用 TLS 1.2 进行连接。
要解决您的问题,请将您的管理工作室安装升级到最新版本,因为它以 .NET 4.6.1 为目标,并将使用 TLS 1.2 作为默认安全协议。
SSMS 下载页面
第二种解决方案是,如果您无法更新到最新版本的 SSMS,您可以进行一些注册表更改,强制 Windows Server 忽略 .NET 3.5 指定的协议并改用 TLS 1.2。我建议不要这样做(如果您无法更新 SSMS,您可能不会被允许更改注册表设置),但为了完整性,我已经包含了这些信息。
有关如何强制 .NET 3.5 使用 TLS 1.2 以及需要更改哪些注册表项的详细信息,请参见下文:
支持 Windows Server 2012 上的 .NET Framework 3.5 中包含的 TLS 系统默认版本