mysql協議分析2---認證包
主人看到navicat和mysql在那嘻嘻哈哈,眉來眼去的,好不快樂,忽然也想自己寫個程式,直接去訪問Mysql,雖然現在已經有很多現成的中介軟體可以直接拿來用了,程式只要負責寫sql語句就行了,但是主人想要自己通過mysql協議直接和mysql通訊,一窺究竟。於是主人找到Mysql說:親愛的mysql,我以前和你交流總要通過第三方的驅動在中間傳話,總感覺我們之間還有一個隔閡,有些話也不方便說,我現在有些心裡話想直接和你交流。。。你說行嗎?
mysql說:當然行啊,mysql受寵若驚,要和我打交道有多種方法比如:TCP/IP,TLS/SSL,Unix Sockets,Shared Memory,Named pipes等,那我們就用TCP/IP的方吧。用tcp協議就繞不開三次握手連線和四次握手斷開,所以呢你和我連線的第一件事就是三次握手連線。
主人尷尬的笑了笑,tcp的三次握手聽到聽說過很多次,但是從沒有真正的理解。。。
mysql從身後丟過來一個便籤:這裡有篇文章可以參考下:https://www.cnblogs.com/zhanyd/p/9877762.html
主人謝道,還是你體貼,剛開始navicat和你連線的時候,我是輸入了主機地址,使用者名稱,密碼的,你們之間是怎麼驗證的呢?
mysql說:好問題,所有的客戶端和我連線首先都要先經過我的認證,我和客戶端一次正常的互動過程如下:
1. 三次握手建立 TCP 連線。 2. 建立 MySQL 連線,也就是認證階段。 服務端 -> 客戶端:傳送握手初始化包 (Handshake Initialization Packet)。 客戶端 -> 服務端:傳送驗證包 (Client Authentication Packet)。 服務端 -> 客戶端:認證結果訊息。 3. 認證通過之後,客戶端開始與服務端之間互動,也就是命令執行階段。 客戶端 -> 服務端:傳送命令包 (Command Packet)。 服務端 -> 客戶端:傳送迴應包 (OK Packet, or Error Packet, or Result Set Packet)。 4. 斷開 MySQL 連線。 客戶端 -> 伺服器:傳送退出命令包。 5. 四次握手斷開 TCP 連線。
我專門搞了個認證報文格式,我會按照以下的格式給客戶端傳送資料,然後客戶端要根據這裡面的內容給我返回驗證包,然後我判斷是否有許可權登入:
官方的文件是這樣子滴:
感覺不直觀,在網上找到一個更直觀的圖:
具體解釋如下:
-
protocol_version (1) --
0x0a
protocol_version第一個位元組表示協議版本號
-
server_version (string.NUL) -- human-readable server version
伺服器版本號,字串遇到Null結束
-
connection_id (4) -- connection id
伺服器執行緒id
-
auth_plugin_data_part_1 (string.fix_len) -- [len=8] first 8 bytes of the auth-plugin data
第一部分8個位元組的挑戰隨機數,後面還有第二部分
-
filler_1 (1) --
0x00
填充位
0x00
-
capability_flag_1 (2) -- lower 2 bytes of the
Protocol::CapabilityFlags
(optional)伺服器權能標誌(低位2個位元組)
-
character_set (1) -- default server character-set, only the lower 8-bits
Protocol::CharacterSet
(optional)This “character set” value is really a collation ID but implies the character set; see the
Protocol::CharacterSet
description.字元編碼
-
status_flags (2) --
Protocol::StatusFlags
(optional)伺服器狀態
-
capability_flags_2 (2) -- upper 2 bytes of the
Protocol::CapabilityFlags
伺服器權能標誌(高位2個位元組)
-
auth_plugin_data_len (1) -- length of the combined auth_plugin_data, if auth_plugin_data_len is > 0
挑戰隨機數的長度
-
string[10] reserved (all [00])
10個位元組的保留位,都是00
-
auth_plugin_data_part_2
挑戰隨機數的第二部分,通常是12位元組
-
挑戰隨機數結束標誌00
-
auth_plugin_name (string.NUL) -- name of the auth_method that the auth_plugin_data belongs to
認證外掛的名稱,null結尾(這部分上面的圖表裡沒有加進去)
主人聽完後,躍躍欲試,很想驗證下Mysql說的是不是真的,於是他找到了密友Wiresshark,讓他監聽下navicat和mysql之間的認證包,Wiresshark很快就完成了任務,把結果呈上來了:
具體先看伺服器傳送過來的第一個包:
主人一看,居然和mysql說的一模一樣,好神奇。。。
mysql笑道:那當然,我還能騙你不成。我發給客戶端收到後,客戶端就要返回認證包給我驗證啦,是驢是馬我一眼就能認出來了哦,客戶端返回給我要遵循以下的格式:
Fields
-
capability_flags (4) -- capability flags of the client as defined in
Protocol::CapabilityFlags
客戶端權能標誌
-
max_packet_size (4) -- max size of a command packet that the client wants to send to the server
報文的最大位元組數
-
character_set (1) -- connection's default character set as defined in
Protocol::CharacterSet
.字符集編碼
-
username (string.fix_len) -- name of the SQL account which client wants to log in -- this string should be interpreted using the character set indicated by
character set
field.使用者名稱
-
auth-response (string.NUL) -- opaque authentication response data generated by Authentication Method indicated by the
plugin name
field使用者認證資訊,即密碼明文和挑戰隨機數加密後的token
-
database (string.NUL) -- initail database for the connection -- this string should be interpreted using the character set indicated by
character set
field.資料庫名稱
-
auth plugin name (string.NUL) -- the Authentication Method used by the client to generate
auth-response
value in this packet. This is an UTF-8 string.認證方法
主人抓包的結果:
mysql收到了主人發過來的認證包:主人,經過驗證使用者名稱密碼都是正確的,可以登入了,我要返回一個ok報文,告訴你操作成功了哦,報文結構如下:
-
header:
OK:
header
= 0 and length of packet > 7header=0並且報文長度>7表示當前是ok報文
EOF:
header
= 0xfe and length of packet < 9header=0xfe並且報文長度<9表示當前是eof報文
主人抓包的結果:
header = 0,表示這個是個ok報文,status_flags(server status)= 02表名設定自動提交成功。
主人很高興:這是不是說明,我和你的連線成功了呀?
mysql:恭喜你連線成功了,我們走出了第一步,接下來你就可以傳送命令讓我執行了喲。