MySQL原生密碼認證
- 2019 年 10 月 4 日
- 筆記
原文地址:
基於密碼的身份認證包括了兩個部分:
- 伺服器端認證資訊的存儲
- 密碼的認證過程
基於密碼的身份認證有一個原則:僅使用人知道密碼。密碼不能被存儲在認證伺服器中,在認證過程中也不能通過網路明文傳輸。因為存儲的資訊可能被竊取或者濫用,網路可能被監聽。這些安全隱患都可能導緻密碼的泄露。下面我們看看MySQL是如何做密碼認證的。
MySQL中存儲的認證資訊
MySQL的mysql.user表中有password欄位,其中存儲的資訊是用來做密碼認證的。當查詢這個欄位時看到如下格式的字元串:
*0D3CED9BEC10A777AEC23CCC353A8C08A633045E
這個字元是什麼呢?它是通過哈希演算法SHA1計算出來的密碼的哈希值。SHA1的哈希值長20位元組,轉換成十六進位的字元串長40位元組。前面有一個固定的*總共佔41位元組。這個哈希值是調用兩次SHA1哈希演算法算出來的哈希值,程式碼中稱為stage2hash。
stage2hash = sha1(sha1(密碼))
從stage2hash是無法推導出密碼的。即便這個哈希值被盜了,不知道用戶的密碼仍然無法認證成功。
MySQL的密碼認證過程
- 伺服器發送scramble到客戶端 當客戶端的連接初始化完成或者收到客戶端的COM_CHANGE_USER命令後,伺服器會發送一個隨機的字元串給客戶端。這個隨機的字元竄程式碼中稱作scramble。它是用來產生一個一次性加密秘鑰的。 key = sha1(scramble|stage2hash) 客戶端和伺服器之間通過這個秘鑰來加密傳輸認證資訊。
- 客戶端發送加密的stage1hash到伺服器 客戶端將收到的scramble和stage2hash一起再次進行哈希,產生出的哈希值用作加密秘鑰。因為stage2hash並沒有在網路上傳輸,只有伺服器和客戶端知道,所以產生的秘鑰也只有伺服器和客戶端知道。 key = sha1(scramble|stage2hash) 接著將stage1hash加密後,發送給伺服器。stage1hash是將密碼用SHA1哈希一次後產生的哈希值。 stage1hash = sha1(密碼) 加密的演算法很簡單,就是一個XOR操作。將key和stage1hash逐位元組做XOR的操作。 密文 = xor(key, stage1hash)
- 伺服器解密stage1hash,並檢查有效性 解密也很簡單,就是將密文與key做XOR操作。 stage1hash = xor(key, 密文) 接著通過stage1hash生成stage2hash stage2hash = sha1(stage1hash) 然後將產生的stage2hash和mysql.user中存儲的哈希值進行比對,如果相同則認證成功,否則失敗。
MySQL的密碼認證的安全性
- 伺服器上的stage2hash被盜 由於盜取人不知道用戶密碼就無法產生正確的stage1hash,因此在伺服器比對stage2hash時會出錯。
- 網路被監聽 通過網路傳輸的只有scramble隨機字元串和加密的stage1hash。因為每次使用的秘鑰都不同,所以監聽者沒辦法獲取stage1hash或者利用這個加密的stage1hash進行認證。要想獲取到stage1hash,監聽者必須同時盜取了伺服器上存儲的stage2hash才行。本質上來說,伺服器認證的是stage1hash。如果***者獲取了stage1hash,就如同獲取了用戶的密碼一樣。