MySQL原生密碼認證

  • 2019 年 10 月 4 日
  • 筆記

原文地址:

http://mp.weixin.qq.com/s?__biz=MzAwMDU2ODU3MA==&mid=2247484640&idx=1&sn=5a25f1e15b505053810581846e895d93&chksm=9ae7b975ad9030635e7adaa82de3ae386ff1c430c226abeb428eb66f597963b1f104dae776db&mpshare=1&scene=1&srcid=0727mNqaxSwmTafhTA0d2ZSN#rd

基於密碼的身份認證包括了兩個部分:

- 伺服器端認證資訊的存儲

- 密碼的認證過程

基於密碼的身份認證有一個原則:僅使用人知道密碼。密碼不能被存儲在認證伺服器中,在認證過程中也不能通過網路明文傳輸。因為存儲的資訊可能被竊取或者濫用,網路可能被監聽。這些安全隱患都可能導緻密碼的泄露。下面我們看看MySQL是如何做密碼認證的。

MySQL中存儲的認證資訊

MySQL的mysql.user表中有password欄位,其中存儲的資訊是用來做密碼認證的。當查詢這個欄位時看到如下格式的字元串:

*0D3CED9BEC10A777AEC23CCC353A8C08A633045E

這個字元是什麼呢?它是通過哈希演算法SHA1計算出來的密碼的哈希值。SHA1的哈希值長20位元組,轉換成十六進位的字元串長40位元組。前面有一個固定的*總共佔41位元組。這個哈希值是調用兩次SHA1哈希演算法算出來的哈希值,程式碼中稱為stage2hash。

stage2hash = sha1(sha1(密碼))

從stage2hash是無法推導出密碼的。即便這個哈希值被盜了,不知道用戶的密碼仍然無法認證成功。

MySQL的密碼認證過程

  1. 伺服器發送scramble到客戶端 當客戶端的連接初始化完成或者收到客戶端的COM_CHANGE_USER命令後,伺服器會發送一個隨機的字元串給客戶端。這個隨機的字元竄程式碼中稱作scramble。它是用來產生一個一次性加密秘鑰的。 key = sha1(scramble|stage2hash) 客戶端和伺服器之間通過這個秘鑰來加密傳輸認證資訊。
  2. 客戶端發送加密的stage1hash到伺服器 客戶端將收到的scramble和stage2hash一起再次進行哈希,產生出的哈希值用作加密秘鑰。因為stage2hash並沒有在網路上傳輸,只有伺服器和客戶端知道,所以產生的秘鑰也只有伺服器和客戶端知道。 key = sha1(scramble|stage2hash) 接著將stage1hash加密後,發送給伺服器。stage1hash是將密碼用SHA1哈希一次後產生的哈希值。 stage1hash = sha1(密碼) 加密的演算法很簡單,就是一個XOR操作。將key和stage1hash逐位元組做XOR的操作。 密文 = xor(key, stage1hash)
  3. 伺服器解密stage1hash,並檢查有效性 解密也很簡單,就是將密文與key做XOR操作。 stage1hash =  xor(key, 密文) 接著通過stage1hash生成stage2hash stage2hash = sha1(stage1hash) 然後將產生的stage2hash和mysql.user中存儲的哈希值進行比對,如果相同則認證成功,否則失敗。

MySQL的密碼認證的安全性

  1. 伺服器上的stage2hash被盜 由於盜取人不知道用戶密碼就無法產生正確的stage1hash,因此在伺服器比對stage2hash時會出錯。 
  2. 網路被監聽 通過網路傳輸的只有scramble隨機字元串和加密的stage1hash。因為每次使用的秘鑰都不同,所以監聽者沒辦法獲取stage1hash或者利用這個加密的stage1hash進行認證。要想獲取到stage1hash,監聽者必須同時盜取了伺服器上存儲的stage2hash才行。本質上來說,伺服器認證的是stage1hash。如果***者獲取了stage1hash,就如同獲取了用戶的密碼一樣。

Tags: