Kerberos和NTLM - SQL Server連線的那點事

apgcdsd發表於2011-09-28

當我們使用Windows Authentication去連線SQL Server的時候,SQL Server可能會使用Kerberos或者是NTLM來進行認證,有時間就會因為認證失敗的緣故造成各種登入錯誤(login failed)。解決這些問題往往令人很迷惑。今天我們就來做一個簡單的介紹。

 1. Kerberos VS NTLM

NTLM認證:Challenge – Response 模式

在使用NTLM協議時,客戶端傳送使用者名稱到伺服器端;伺服器生成一個challenge併傳送給客戶端;客戶端使用使用者的密碼來加密這個challenge,然後傳送response到伺服器端。如果該賬號是一個本機賬號,那麼伺服器使用Security Account Manager來驗證使用者;如果賬號是一個域賬號,那麼伺服器把這個response請求轉送到域控制器(DC)上來讓域控制器呼叫組安全策略來做使用者認證,然後伺服器就可以構建一個安全令牌並建立一個session

Kerberos認證:Trust-Third_party架構

Kerberos認證提供一種伺服器和客戶端相互認證的機制。Kerberos包含了三個關鍵元件:Key Distribution Center (KDC)客戶端使用者,和一個執行所需服務的伺服器。KDC是域控制器的一部分,它執行兩個任務:認證服務(AS)和票據許可服務(TGS)。當客戶端使用者登入到網路上時,它會向使用者所在域的AS去請求一個“票據請求票據”(TGT)。然後,當客戶端想要訪問網路上的某個資源的話,它就出示以下東西:TGT,認證碼,Server Principal NameSPN);有了這些東西,客戶端就可以從服務所在的域中的TGS獲得session票據。使用這個session票據,客戶端就可以和網路上的服務進行交流,該服務會驗證“認證碼”然後建立一個訪問令牌給客戶端使用者,接下來客戶端就可以登入上該服務了。


 
2. KerberosNTLM認證的要求

Kerberos的要求:

1) 客戶端和伺服器端一定要加入域,如果客戶端和伺服器端在不同的域的話,這兩個域一定要被配置滬入域,如果客戶端和伺服器端在不同的域的話,這兩個域一定要被配置被互相信任。

2) 註冊SPNSPN是伺服器上所執行服務的唯一標示。每個使用Kerberos的服務都需要一個SPN,這樣客戶端才可以辨認這個服務。SPN是註冊在AD上的機器賬戶或者是域使用者賬戶下的。比如,如果SQL Server執行在Local SystemNetwork Service賬戶下,那麼SPN就需要註冊在機器賬戶下。如果SQL Server執行在域使用者下,則SPN就需要註冊在該域使用者下。

這個順便提一下。當一個服務執行在Local SystemNetwork Service下的時候,我們稱該服務執行在機器帳戶下。因為,從AD的角度來看,每臺機器的Local SystemNetwork Service都代表了這條機器本身,而機器本身也是一種使用者,叫做機器帳戶。

SPN

一個SQL ServerSPN由以下元素組成:

·       服務型別:它標示了服務的泛用類。對於SQL Server而言,它永遠是MSSQLSvc

·       主機:它有兩種形式。一個是執行SQL Server的計算機的fully qualified domain name (FQDN)。還有一種就是SQL Server的計算機的netbios名字,俗稱短名。

·       埠號/例項名:服務所監聽的計算機埠號。對於SQL Server而言,如果SQL執行在預設埠(1433)上,則埠號可以省略。

SQL Server 2008開始,Kerberos可以支援TCP, Named PipesShared Memory三種協議。因此對於SQL Server 2008我們也可以使用SQL Server的例項名來替代埠號(僅就命名例項而言)。

一些例子是:

MSSQLSvc/myserver.corp.mycomany.com:1433

MSSQLSvc/myserver:1433

MSSQLSvc/myserver.corp.mycomany.com

MSSQLSvc/myserver:

MSSQLSvc/myserver.corp.mycomany.com:instancename

MSSQLSvc/myserver:instancename

要注意的是,我們推薦為FQDNnetbios都分別註冊SPN。這是因為有的客戶端程式可能會使用短名的SPN來請求session ticket,但有的程式會使用FQDNSPN來請求session ticket,有時候我們很難預見到應用程式到底想要哪種SPN。保險起見我們建議,為FQDNnetbios都註冊上SPN

NTLM

NTLM需要使用者的密碼來構建Challenge-Response,這樣客戶端才可以在不需要把密碼通過網路傳送到伺服器端的情況來證明自己。所以說,如果你的客戶端應用程式執行在機器賬戶下(比如local systemnetwork service等),會發生什麼呢J

要測試NTLM是否正常。可以使用以下命令:

"net view \\server", or "net view \\ipaddress"

NTLM Fallback

Windows使用一種被稱為negotiate (SPNEGO)的演算法來協商應該使用哪種認證方式。當連線SQL Server時,客戶端驅動解析SQL ServerDNS名字然後組成它是以想要的SPN,講這個SPN交給SPNEGO,讓SPNEGOKDC上去查詢是否有合適的SPN,並以此來決定使用KeberosNTLM。從Windows Server 2003開始,Kerberos都是預設的認證方式。但是當Kerberos失敗的時候,可能會去嘗試使用NTLM,這就被稱為fallback。為什麼要說“可能”呢?

因為當網路上有沒有SPN註冊時候,這個時候Fallback才會發生。當網路上有SPN註冊,但是如果註冊SPN的賬號不是SQL Server服務賬號(也就是說ADSPN確實存在,但是註冊在了錯誤的賬號下),這個時候,無論是否存在一個被註冊在正確的SQL Server服務賬號下的SPNKerberos都會失敗,而這種失敗是不會fallbackNTLM上的。也就是說這種情況下,無論NTLM是不是可以用,認證都會直接失敗。

 

3. SQL Server什麼時候用NTLM什麼時候用Kerberos

當客戶端使用Windows認證來連線SQL Server時(例如,連線字串中有integrated security或者trusted connection字樣的話)。

SQL Server 2000/2005

1) 當有正確的SPN被註冊情況下,使用TCP協議來做遠端連線時會使用Kerberos

2) Windows XP的系統上,如果有正確的SPN註冊,使用TCP協議來做本地連線時也會用Kerberos

3) Windows 2003/2008上,做本地連線時會使用NTLM

4) 使用named pipes連線時,會使用NTLM

5) 當沒有找到SPN時,TCP連線會使用NTLM

6) 當域中存在錯誤的SPN時,認證失敗。

SQL Server 2008/2008 R2

1) SPN被對映到正確的域或者內建機器賬號時 (Local System, Network Service)本地連線會使用NTLM,而遠端連線會使用Kerberos

2) SPN就是正確的域或內建系統賬號的時候,本地和遠端的連線都會使用Kerberos

3) 當沒有找到SPN時,TCP連線會使用NTLM

4) 當域中存在錯誤的SPN時,認證失敗。

檢查是否有正確的SPN存在

我們首先要下載setspn.exe工具。

http://www.microsoft.com/downloads/details.aspx?FamilyID=5fd831fd-ab77-46a3-9cfe-ff01d29e5c46&DisplayLang=en

然後在命令列中輸入:

Setspn –L

Account可以是一個域使用者也可以使一個機器名

a. 如果你的SQL Server是使用Local System或者Network Service啟動的話,<Acount>處就填寫SQL Server所在機器的機器名。Local System或者Network Service

b. 如果SQL Server是使用域使用者啟動的話,那麼<Acount>處就填寫該域使用者名稱即可。

輸出結果可以告訴你是否有正確的(註冊在正確帳戶下的)SPN存在。

新增SPN

如果SPN不存在,那麼我們可以使用setspn.exe來新增SPN。要注意,如果你當前登入的賬號不是域管理員但卻是本機管理員的話,預設情況下你是有為本賬號註冊SPN的許可權的(但是你不能為其他賬號註冊SPN)。如果你無法使用SQL Server服務賬號來登入Windows,或者你的賬號不是本機管理員,你就需要聯絡你的域管理員來執行以下命令來註冊SPN

Setspn A MSSQLSvc/myserver.corp.mycomany.com:instancename 

此處setspn –L的用法是一樣。

需要提的是,SQL Server在啟動的時候,會自動嘗試到AD中註冊它的SPN。當服務停止的時候,SQL Server會嘗試登出該SPN。但是預設情況下,域的安全策略只賦予了機器賬號以註冊SPN的許可權。也就是說,只有當SQL Server在用Local System帳戶啟動時,它才會有足夠的許可權來成功註冊和登出SPN。如果SQL Server是用域帳戶啟動的話(比如說,SQL群集一定要使用域帳戶才能啟動),則預設情況下我們不得不手工的執行Setspn –A命令來為SQL Server註冊SPN(當然域管理也可以開放註冊SPN的許可權給那個SQL Server用的域賬號,但是這種情況並不多見)。如果自動註冊和登出SPN失敗的話,在SQL ServerERRORLOG中會有一段警告資訊。

這樣的自動序號產生器制帶來了一個隱藏的問題。就是域中可能存在SPN但是你從未意識到。假設一開始SQL Server的啟動帳戶是local system帳戶,那麼在你沒意識到的情況下,SQL ServerSPN就被註冊到了域中的機器帳戶下。這個時候Kerberos會執行的很正常,給你的感覺是你不需要做額外配置Kerberos也能執行。但是如果以後SQL Server的啟動帳戶被改為域使用者,你會發現Kerberos突然不能正常工作了。而且此時即使你手動為該域使用者註冊了一個SPNKerberos也無法成功。那是因為在域中存在了一個錯誤的SPN,就是之前註冊在機器帳戶下的那個SPN。此時我們一定要刪除那個錯誤的SPN

刪除SPN

刪除SPN的許可權要求和新增SPN是一樣的。命令列是:

Setspn –D MSSQLSvc/myserver.corp.mycomany.com:instancename 

如何發現存在錯誤的SPN

前面提到,如果存在錯誤的SPN的話,那麼或導致認證直接失敗而不會fallbackNTLM。那麼如何發現有錯誤的SPN存在呢?有兩種方法:

1) 使用工具ldifde

Ldifde可以根據你的需求,把域環境中所有的SPN都輸出出來。以下是一個例子。

ldifde -f C:\SPNs.txt -t 3268 -d dc= mycompany,dc=com -l serviceprincipalname -r (serviceprincipalname=MSSQLsvc*) -p subtree

使用以上命令,可以把mycompany.com域中所有的以MSSQLSvc開始的SPN都匯出到C:\SPNs.txt檔案中去。這樣我們就可以開啟SPNs.txt去檢視是否有錯誤的SPN存在了。

2) Setspn –X

Windows Server 2008開始,setspn有了新的選項-X。使用-X選項就可以查詢域中是否存在重複的SPN。所謂重複的SPN值得是註冊在不同賬戶下的相同SPN。那麼則重複的SPN中至少有一個是錯誤的(也可能都是錯誤的)。

如何確認客戶端使用Kerberos連線到了SQL Server

最簡單的辦法,是當連線建立後去查詢SQL Server中的一個DMVsys.dm_exec_connections。該DMV有一個列叫auth_scheme。該列會顯示對應的連線所使用到底是NTLM還是Kerberos

除了DMV之外,我們當然還可以通過在客戶端和伺服器端中間抓取網路包,然後分析網路包來判斷使用的認證方式是哪一個。

此外,微軟客戶支援有一個內部工具叫SSPIClient,使用該工具去連線SQL Server, 它的log不但可以獲知使用了什麼協議來連線SQL Server,還能告訴為什麼Kerberos失敗了(如果失敗的話)。這樣就可以採用有效的手段來解決阻礙Kerberos執行的問題。

 

4. 什麼時候我們需要Kerberos

既然NTLMKerberos都可以作為認證的方式,那為什麼我們需要花大工夫來配置SPN使得Kerberos可以工作呢?為什麼Windows預設先嚐試Kerberos,只有當Kerberos失敗時才會嘗試NTLM?

我們推薦使用Kerberos來作為SQL Server的連線協議,至少是可以獲得三種好處。

1) 安全性上的優勢。NTLM在面對一些安全攻擊的時候還是相對脆弱,比如它不能很好的防範中間人(man-in-the-middle)的攻擊。一些使用Kerberos的關鍵優勢,可以從這裡找到。

http://msdn.microsoft.com/en-us/library/cc280744.aspx

2) 有一些應用程式,包括微軟的SCCMSCOM等,是要求執行在Local System帳戶下的。Local System賬號會使得NTLM無法工作。這個時候我們就需要把Kerberos配置通才能使得應用程式可以成功登陸SQL Server

3) 在所謂的double-hop的應用場景下,我們需要使用委託的功能把客戶端的身份資訊傳送到最後端的SQL Server。此時只有Kerberos才能完成“委託”的重任。否則在最後端的SQL Server就會收到一個登陸失敗的提示。Double-hop和委託又是一個很大的概念,他們的配置方式在本文中就不詳細展開了。有興趣的話,可以去參閱以下文章及其擴充套件連線,內容非常詳細。

http://www.microsoft.com/download/en/details.aspx?id=4754

http://blogs.msdn.com/b/sql_protocols/archive/2006/08/10/694657.aspx

 

5. 常見問題

[1] "Login Failed for user 'NT Authority\ANONYMOUS' LOGON"

這個時候客戶端很可能是執行在Local System帳戶下的,而且SQL Server沒有註冊SPN。於是,NTLM就被使用了。而由於Local System賬號繼承自System Context而不是一個真實的user context,於是就被當成ANONYMOUS LOGON

解決方法就是在SQL Server的服務帳戶下手工註冊SPN

 [2] "Login Failed for user ' ', the user is not associated with a trusted SQL Server connection".

或者"Login Failed for user '(null)', the user is not associated with a trusted SQL Server connection".

這種情況下,很明顯就是客戶端使用者沒能被SQL Server識別出。

對於這個問題,解決方案要分兩種情形。

1) 如果客戶端程式是執行在一個本機使用者(非域使用者)或者是一個非本機管理員許可權的機器帳戶(非local system)下,那麼無論SQL Server是否有註冊SPN,都會得到這個錯誤。那麼解決方案就是:

在伺服器端建立一個和客戶端使用者“同使用者名稱用密碼”的本機賬號,然後在SQL Server中賦予相應的登入許可權。這就是所謂pass through的方式。此時你實際上是在使用SQL Server那臺計算機的同名帳戶來訪問SQL Server和相關的其他資源。因此SQL Server機器上該帳戶的許可權設定決定了客戶端的操作許可權。

2) 如果客戶端應用程式是執行在一個域使用者下的話,那麼該錯誤就說明Kerberos的驗證失敗了,這往往是由於沒有SPN或者SPN不正確造成的。這個時候你可以選擇一下兩個方案中的一個:

a. 建立正確的SPN,使得Kerberos能成功。

b. 乾脆讓客戶端用NTLM來連線SQL Server。你可能需要去檢查AD,如果有發現錯誤的SPN就刪掉。

[3] "Could not open a connection to SQL Server[1326]"

和錯誤[2]一樣的問題,只不過[2]是發生在TCP連線上的,[3]一般是發生在Named Pipe連線上的。

[4] "Login failed for user '\<machinename>$' "

這種情況下,你的客戶端程式是使用Local system或者Network service執行的,最簡單的解決辦法就是在SQL Serverlogin中新增一個"domain\machinename$"賬號。Machinename就是客戶端的機器名。

[5] Cannot generate SSPI Context.

這是一個典型的Kerberos認證失敗。造成這種錯誤的原因多種多樣,最常見的還是SPN的問題,也發現過很多由於KDC工作不正常,或者TGS服務異常導致該錯誤的案例。我建議大家看一下這篇KB,寫的比較全面:

http://support.microsoft.com/?id=811889

這裡有兩篇部落格供參考:

http://blogs.msdn.com/b/sql_protocols/archive/2005/10/15/481297.aspx

http://blogs.msdn.com/b/sql_protocols/archive/2005/10/19/482782.aspx

 

明明都配置好了,為什麼Kerberos就是不工作呢?

要提醒大家的是,在解決Kerberos相關問題的時候,我們可能會遇到這種情況:明明kerberos所需的所有條件都配置好了,但是測試連線時仍舊一直得到Kerberos錯誤或者是NTLM錯誤。這個時候大家不妨試一下如下兩招:

1) 在一個域環境中可能存在多個DC,我們在troubleshooting的時候做的一系列改變只會作用在其中某一臺DC上。有可能客戶端連線SQL Server時使用的是另外一臺DC,而此時這臺DC還沒有同步到你之前所做的那一系列改變。這個時候,我們不需要等DC間的自動同步發生,可以執行以下語句來強制DC間作同步:

Repadmin /syncall

2) Credential Cache也可能會是問題。Credential CacheKerberos用來在本機上快取認證資訊的。他主要包含TGTSession票據。由於Credential Cache在本機上有一段的生存週期(通常是10小時),因此如果之前客戶端得到過不正確的認證資訊並快取起來的話,在快取過期前就會一直使用這個資訊來訪問SQL Server,於是就一直會得到錯誤。解決方法是以下3個辦法中的任何一個來清除Credential Cache

a. klist.exe –purge命令

b. kerbtray工具

c. 重啟整個機器。

 

認證和授權的區別

認證(authentication)的錯誤,包括 Login failed for user ‘’, Login failed for user ‘(null)’,或者ANONYMOUS LOGON。我們常見的18452錯誤就是認證錯誤。

當你看到Login failed for user 時,這其實是一個授權(authorization)錯誤。此時,SQL Server已經識別出了要求登入使用者,但是由於SQL Server內部的安全相關的設定,登入操作沒有成功。我們常見的18456錯誤就屬於這類錯誤。

Ø  Error: 18456, Severity: 14, State: XX.

 

我們可以通過State:XX來判斷到底是什麼原因導致的授權失敗。但是,由於擔心惡意的客戶端可能通過state來猜測失敗原因並採取相應手段來攻擊伺服器,State是不能返回客戶端的。它會被寫入SQLERROELOG檔案。

失敗state對應的原因:

1 通用錯誤

2 遠端登入的登入在伺服器中不存在

34 解密記憶體中加密的密碼失敗

5 SQL登入不存在

6 連線的SQL登入不符合登入型別列表

7 登入功能關閉

8 密碼不符合

9密碼不可用(登入時正在修改密碼)

10 賬戶策略驗證失敗

如果以下密碼策略檢查評估返回假:

1)登入成功

2)密碼已過期

3)使用者需要更改密碼

然後我們設定登入狀態,並返回一個失敗state10

11 windows驗證沒有被授權可以連線

12 SQL驗證沒有被授權可以連線

13 伺服器暫停,禁止所有登陸

14 登入不能用於此連線的介面型別

15 連線字串中指定的資料庫無效

16個預設資料庫是無效的

17預設語言為無效

18這種登入型別密碼不能改變

19無法解密加密的記憶體中的新密碼

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25175503/viewspace-708444/,如需轉載,請註明出處,否則將追究法律責任。

相關文章