昨天有個自稱 ASP.NET Web Form 界最強的大作者,寫了一篇文章,裡面說使用 Windows 驗證連線資料庫是最不建議的作法,但這只是凸顯該大作者一點都不懂資訊安全的其中一個點而己,殊不知他認為的最不建議的作法,卻是 Microsoft 官方最建議的作法。
SQL Server 的帳戶驗證有兩種方式,一種是 Windows 驗證,採用 NTLM 或 Kerberos,使用 Windows 帳戶 (也就是那位大作者所說的 XXX\yyy,XXX 是電腦名稱或網域名稱,yyy 是使用者名稱) 驗證身份;另一種是 SQL Server 驗證 (更常聽到的是 SQL 驗證),帳戶是建在 SQL Server 裡面,應用程式需傳遞帳戶與密碼到 SQL Server 進行驗證。
這兩種驗證方法最主要的差異是,Windows 驗證採用 NTLM/Kerberos 協定進行驗證,傳遞的是使用者驗證的 hash 而不是使用者帳戶名稱與密碼,相對 SQL 驗證而言更安全,也是 Microsoft 官方建議的驗證方式,SQL 驗證由於要傳遞帳戶名稱與密碼 (可逆型的簡單編碼),對網路傳輸間安全性 (transport-level security) 的要求更高,另一個不安全的原因是帳戶名稱與密碼必須寫在連線字串 (connection string) 內,只要能打開 app.config 或 web.config 基本上就能看到資料庫的帳密資料,光是這點就很危險了,雖然微軟有提供連線字串加密機制 (connection string encryption),但我相信真的沒多少人做。
另外,Kerberos 會比 NTLM 再高一階的安全性,是因為驗證與證明使用者與服務端身份的機制更複雜也更完整,使得傳遞的訊息也是經過加密的,在經過一連串的身份驗證後,才會正式進行通訊。其細部的資訊可參考維基百科。Windows 的 Active Directory 採用的是 Kerberos V5 的協定。
在此感謝曹祖聖老師的補充。
因此基本上最佳的安全方法,反而是使用 Windows 驗證。
但是那位大作者的文章裡面是這樣寫的 (retrived at 2017/7/13 AM 9:20):
這種講法就是典型不懂資訊安全,甚至是視資訊安全為無物的講法,不用說嚴重誤導讀者,有些還根本做不到,例如 IIS 一般的使用帳戶名稱是 IIS AppPool\[pool name],請問使用者要去哪生 IIS AppPool 出來? 如果真建了這個帳戶又是否會和 IIS 原本的設定衝突?
真是夠了。
不過我還是要說明一下 Windows 驗證和 SQL Server 驗證的優缺點,讓讀者自己比較。
Windows 驗證:
- 優:帳戶密碼不會暴露在連線字串內 (設定 Integrated Security=true 或 Integrated Security=SSPI)。
- 優:在網域環境內可使用網域帳戶來統一分散式環境 (例如,在多 Web Server 的環境,於每台 IIS 上的 app pool identity 設定同一個網域帳戶)。
- 優:可於本機帳戶管理或網域帳戶管理中停用帳戶以關閉存取權,以及套用群組原則來落實管理與控制政策。
- 優:可使用直接讀取使用者登入帳戶的方式,由使用者自己的帳戶存取資料庫。當然實務上這會使管理負擔增加,因此還會外加一個模擬帳戶的方式來存取資料庫。
- 缺:需要額外的管理負擔來管理帳戶。
- 缺:在網域環境內,網域控制站必須活著 (online),否則可能會拖慢速度或無法使用。
- 缺:需要額外的設定知識 (例如設定 IIS application pool 帳戶)。
SQL Server 驗證:
- 優:較簡單,只要在 SQL Server 建立帳戶,然後將帳戶密碼寫在連線字串即可,不需要特別設定 IIS application pool 帳戶。
- 優:SQL Server 帳戶與 Windows 帳戶無關,因此對 Windows 帳戶的異動不會影響到 SQL Server 存取 (但這也有一個缺點,就是無法利用群組原則落實管理與控制政策)。
- 缺:帳戶密碼暴露在連線字串,有被盜的風險,尤其是很多人圖方便會直接用 sa 帳戶,等於雙手奉上伺服器存取權給惡意使用者。
- 缺:若安裝 SQL Server 時沒有啟用 SQL Server 驗證,需要額外的步驟才能啟用。
- 缺:傳遞帳戶密碼時可能是以未加密的傳輸,一樣會有帳戶密碼被攔截竊取的風險,可以啟用 SQL Server SSL,但會有管理成本。
我的建議是,能用 Windows 驗證就用 Windows 驗證,除非不在網域環境且主控權不高的情況下,才使用 SQL Server 驗證,同時必須要求下列安全事項:
- 不得使用具有操作伺服器與資料庫組態的帳戶,例如 sa、具 sysadmin 權限的帳戶、具 db_owner 權限的帳戶等。
- 應盡量使用連線字串加密,以保護使用者帳戶名稱與密碼。
- 可以的話,啟用傳輸加密,以保護帳戶名稱與密碼在網路上的傳輸安全。
- 資料庫伺服器和用戶端不可跨越 Internet,除非已落實適當保護措施。
千萬不要因為自己懶,反而讓資料庫裸奔,那會讓你更慘。