1. 程式人生 > >mysql協議分析2---認證包

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 > 7

    header=0並且報文長度>7表示當前是ok報文

    EOF: header = 0xfe and length of packet < 9

     header=0xfe並且報文長度<9表示當前是eof報文

     

主人抓包的結果:

header = 0,表示這個是個ok報文,status_flags(server status)= 02表名設定自動提交成功。

 

 

主人很高興:這是不是說明,我和你的連線成功了呀?

mysql:恭喜你連線成功了,我們走出了第一步,接下來你就可以傳送命令讓我執行了喲。