概述
MongoDB客戶端在建立服務連接時的認證過程,根據所采用的認證方式,可能會有所不同,社區版MongoDB通常支持SCRAM(Salted Challenge Response Authentication Mechanism)鹽化挑戰響應身份驗證機制和基于X.509證書的認證,而企業版MongoDB還提供了與許多外部身份驗證機制的集成,如Kerberos和LDAP等。從MongoDB 3.0開始,SCRAM成為了MongoDB的默認身份驗證機制,不同的認證方式也可以通過配置文件或啟動參數來啟用。
SCRAM認證簡介
SCRAM(Salted Challenge Response Authentication Mechanism)是一種基于加鹽哈希和HMAC摘要的用于客戶端和服務器之間的用戶認證機制,它通過一個挑戰-響應協議來驗證用戶的身份。SCRAM是MongoDB的默認認證機制,并且被設計為既安全又易于實現。下面介紹SCRAM認證的基本概念和認證步驟。
基本概念
- 用戶名(Username):用戶的唯一標識符。
- 密碼(Password):用戶的認證憑據,存儲時會經過處理。
- 鹽(Salt):一個隨機值,用于與密碼結合生成存儲的憑證,增加密碼存儲的安全性。
- 迭代次數(Iteration Count):密碼處理時的迭代次數,增加密碼哈希的計算復雜度。
SCRAM認證步驟
- 客戶端發送用戶名:客戶端首先向服務器發送包含用戶名的請求。
- 服務器發送挑戰:服務器收到請求后,會生成一個隨機的挑戰(server-nonce),這個挑戰是隨機生成的,通常是一個足夠長的隨機字符串,以確保安全性。
- 客戶端生成響應:
- 客戶端接收到挑戰后,會使用用戶的密碼和服務器提供的鹽以及迭代次數來生成一個密碼驗證器(Password Verifier)。
- 客戶端使用密碼、鹽和迭代次數通過一個單向函數(通常是SCRAM-SHA-1)生成一個存儲密鑰(Stored Key)。
- 然后,客戶端使用存儲密鑰和挑戰來生成客戶端證據(Client Evidence),通常是對存儲密鑰和挑戰的HMAC。
 
- 服務器驗證響應:
- 服務器接收到客戶端的證據后,會使用存儲在數據庫中的密碼驗證器和客戶端發送的挑戰來生成服務器證據。
- 服務器比較客戶端證據和服務器證據,如果兩者匹配,則認證成功。
 
- 服務器發送成功或失敗消息:如果認證成功,服務器會發送一個成功的消息給客戶端;如果失敗,會發送失敗的消息。
在SCRAM認證中,第2步驟中的隨機數(server-nonce)的生成是非常重要的,因為它增加了認證過程的安全性。MongoDB中是利用操作系統提供的API,通過標準庫函數讀取/dev/urandom文件來獲取隨機數。在Linux系統中,/dev/urandom 是一個特殊文件,它提供了一個偽隨機數生成器(PRNG),用于生成加密安全的偽隨機數。雖然它是偽隨機的,但被認為是加密安全的,因為其生成的隨機數序列對于所有實用目的來說都是不可預測的。
認證示例
初始
- 服務端使用一個salt和一個iteration-count,對password進行加鹽哈希(使用H表示哈希函數,這里就是SHA1,iteration-count就是哈希迭代次數),得到一個password[s]:
*password[s] = H(password, salt, iteration-count)*
- 服務端拿這個password[s]分別和字符串『Client Key』和『Server Key』進行計算HMAC摘要,得到一個key[c]和一個key[s]:
*key[c] = HMAC(password[s], "Client Key")
key[s] = HMAC(password[s], "Server Key")*
- 服務端保存username、H(key[c])、key[s]、salt和iteration-count,沒有保存真正的password
認證
- 客戶端發送client-first-message給服務端,包含username和client-nonce,其中client-nonce是客戶端隨機生成的字符串。
- 服務端返回客戶端server-first-message,包含salt,iteration-count和client-nonce|server-nonce,其中server-nonce是服務端隨機生成的字符串。
- 客戶端發送client-final-message給服務端,包含client-nonce|server-nonce和一個proof[c]。這個proof[c]就是客戶端的身份證明。首先構造出這次認證的變量Auth如下:
Auth = client-first-message, server-first-message, client-final-message(without proof[c])
然后使用從服務端獲取的salt和iteration-count,根據已知的password計算出加鹽哈希password[s],然后根據password[s]得到key[c],再拿這個key[c]和Auth變量經過如下計算得到:
proof[c] = key[c] XOR HMAC(H(key[c]), Auth)
- 服務端使用其保存的H(key[c])和Auth計算HMAC摘要,再和proof[c]進行異或,得出key[c],再對這個key[c]進行哈希,和其保存的H(key[c])進行比較是否一致。如果一致,則客戶端的認證通過,服務端接下來會構造一個proof[s]用來向客戶端證明自己是服務端:
*proof[s] = HMAC(key[s], Auth)*
- 客戶端使用password[s]得到key[s],然后使用相同算法計算key[s]和Auth的HMAC摘要,驗證服務端發送過來的proof[s]是否和計算出來的一致,從而認證服務端的身份。