mysql 协议说明_MySQL认证协议_MySQL
本文是針對MySQL 5.5.9寫的。MySQL協議是向老版本兼容的。老版本的MySQL Client可能不理解下面的某些字段而忽略掉。
實際使用的時候,服務器的協議版本應當大于等于客戶端。遺憾的是,MySQL并沒有對每一次協議變動標一個數字。
本文中所說的”字節”一詞,英文是Byte。遵循C語言中定義,即char的大小。注意:沒有規定1字節一定等于8位。所以如果你準備在1字節不等于8位的環境中使用mysql,那是給自己找事。
我祈禱你的char是有符號的。
參考http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol(我也參與這個頁面的編輯)
一、客戶端連接服務器的流程
請參見sql-common/client.c的CLI_MYSQL_REAL_CONNECT函數。使用系統的socket函數建立一個socket,然后連接服務器。
使用這個socket初始化一個vio對象
net-vio= vio_new(sock, VIO_TYPE_TCPIP, VIO_BUFFERED_READ);
使用vio初始化net對象
my_net_init(net, net-vio)
并對vio設置為keep alive
vio_keepalive(net-vio,TRUE);
然后設置各種參數
客戶端接下來的流程可分為三個階段:Connection established, read and parse first packet
invoke the plugin to send the authentication data to the server
authenticated, finish the initialization of the connection
二、服務器處理連接
服務器啟動的時候是在sql/mysqld.cc的network_init函數建立socket,然后bind。服務器專門有一個線程(可稱為Connection Manager)處理新來的網絡連接。這個線程的主函數是sql/mysqld.cc的handle_connections_sockets_thread,主要的邏輯在sql/mysqld.cc的handle_connections_sockets。handle_connections_sockets的邏輯就是典型的select()/accept()/dispatch。每個客戶端連接最終會對應著一個線程以及一個THD對象。THD類不是一個通用的描述任意線程的類,它就是專門為處理客戶端的的TCP連接而設計的。這個類非常大,在sql/sql_class.h中定義。
每個worker線程的入口函數是在sql/sql_connect.cc中的handle_one_connection。sql/sql_parse.cc的do_command從網絡連接上讀一個command,并執行。handle_one_connection函數是以while循環的方式執行do_command。
三、協議
客戶端發給服務器的包可分為兩種:登錄時的一個auth包,以及身份驗證結束后的command包。
服務器發給客戶端的包可分為四種:登錄時的握手包、數據包、數據流結束包、成功包(OK Packet)、錯誤信息包。
所有的包都具有統一的格式,由統一的函數(sql/net_serv.cc:my_net_write(…))寫入buffer等待發送。長度描述
3包長度(單位:字節)。按低字節低址的規則存放。因為一共就3個字節,所以單個包的最大長度是(2的16次方-1)字節,約等于16MB。最小長度是0。
1序號。第一個是0。
ndata。
實際上,包長等于 2的16次方-1的包也會被拆成2個包發送。因為Mysql最初沒有考慮突破16M,也沒有預留任何字段做標志這個包的數據不完整。所以只好把長度為2的16次方-1的包視做不完整的包,直到后面收到一個長度小于2的16次方-1的包,然后拼起來。所以最后一個包的長度有可能是0。
登錄
服務器在每收到一個新的連接的時候,會使用sql/sql_connect.cc的login_connection函數作身份驗證。先根據IP做acl,然后才進入用戶名密碼驗證階段。mysql的登錄協議是經典的CHAP協議,sql/sql_acl.cc的native_password_authenticate函數的注釋簡單了解釋了這個協議:the server sends the random scramble to the client.
client sends the encrypted password back to the server.
the server checks the password.
random scramble在4.1之前的版本中是8字節整數,在4.1以及后續版本是20字節整數。它是由password.c的create_random_string函數生的,因為它采用的是rand()%94+33這樣的方式生的,所以scramble的每個字節一定是[33,127)之間的ASCII字符,在協議中發送時,是加上’/0’之后發的(這個后面會詳細解釋)。
命令—答復
在身份驗證之后,服務器和客戶端之間處于一問一答的模式。 截至到Mysql 5.5.9,mysql server一共支持30種command,sql/sql_parse.cc的 dispatch_command函數寫了一個大大的switch…case來處理它們。COM_SLEEP
COM_QUIT
COM_INIT_DB
COM_QUERY
COM_FIELD_LIST
COM_CREATE_DB
COM_DROP_DB
COM_REFRESH
COM_SHUTDOWN
COM_STATISTICS
COM_PROCESS_INFO
COM_CONNECT
COM_PROCESS_KILL
COM_DEBUG
COM_PING
COM_TIME
COM_DELAYED_INSERT
COM_CHANGE_USER
COM_BINLOG_DUMP
COM_TABLE_DUMP
COM_CONNECT_OUT
COM_REGISTER_SLAVE
COM_STMT_PREPARE
COM_STMT_EXECUTE
COM_STMT_SEND_LONG_DATA
COM_STMT_CLOSE
COM_STMT_RESET
COM_SET_OPTION
COM_STMT_FETCH
COM_DAEMON
四、服務器的握手包
客戶端執行recv,會收到一個來自server的包,其中第一個字節是協議的版本號。其它的重要信息還有connection id、scramble
41 00 00 00
0A 35 2E 30 2E 32 30 2D 73 74 61 6E 64 61 72 64 2D 6C 6F 67 00 44 8E 4E 00 5A 66 72 2A 79 43 24 27 00 2C A2 08 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 7B 29 58 5E 50 56 41 21 7C 73 4C 00
其格式如下:(來自sql_acl.cc的send_server_handshake_packet函數的注釋)長度說明
1協議的版本號 (0x0A)
n以0結尾的字符串。描述服務器版本
4thread id
8scramble的前8個字節
10x00。也就是說讓scramble看起來是一個以0結尾的字符串
2server capabilities的低兩個字節。
1server character set
2server status
2server capabilities的高兩個字節。
1scramble的總長度
10保留。必須以0填充。
n(至少12)scramble的剩余部分。(不包含’/0’)
10x00。也就是說讓scramble看起來是一個以0結尾的字符串
server capabilities表:名字從右往左數第幾位說明
CLIENT_LONG_PASSWORD1new more secure passwords
CLIENT_FOUND_ROWS2Found instead of affected rows
CLIENT_LONG_FLAG3Get all column flags
CLIENT_CONNECT_WITH_DB4One can specify db on connect
CLIENT_NO_SCHEMA5Don’t allow database.table.column
CLIENT_COMPRESS6Can use compression protocol
CLIENT_ODBC7Odbc client
CLIENT_LOCAL_FILES8Can use LOAD DATA LOCAL
CLIENT_IGNORE_SPACE9Ignore spaces before ‘(‘
CLIENT_PROTOCOL_4110New 4.1 protocol
CLIENT_INTERACTIVE11This is an interactive client
CLIENT_SSL12Switch to SSL after handshake
CLIENT_IGNORE_SIGPIPE13IGNORE sigpipes
CLIENT_TRANSACTIONS14Client knows about transactions
CLIENT_RESERVED15Old flag for 4.1 protocol
CLIENT_SECURE_CONNECTION16New 4.1 authentication
CLIENT_MULTI_STATEMENTS17Enable/disable multi-stmt support
CLIENT_MULTI_RESULTS18Enable/disable multi-results
CLIENT_PS_MULTI_RESULTS19Multi-results in PS-protocol
CLIENT_PLUGIN_AUTH20Client supports plugin authentication
CLIENT_SSL_VERIFY_SERVER_CERT31
CLIENT_REMEMBER_OPTIONS32
五、然后客戶端將密碼等發送過去
客戶端根據服務器發給的scramble對原始密碼進行散列,然后和其它參數一起發給服務器
發送登錄數據:
00000000 3A 00 00 01 85 A6 03 00 00 00 00 01 08 00 00 00
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000020 00 00 00 00 72 6F 6F 74 00 14 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00長度說明
4client capabilities
4max packet size
1charset number
23保留。必須以0填充。
nuser name。以0結尾的字符串
nhash過的密碼。length (1 byte) coded
ndatabase name,以0結尾的字符串。只有client capabilities中有CLIENT_CONNECT_WITH_DB時,此字段才有效。
nclient auth plugin name。以0結尾的字符串。只有client capabilities中有CLIENT_PLUGIN_AUTH時,此字段才有效。如果使用mysql默認的auth機制,此處應該為mysql_native_password
sql-common/client.c的send_client_reply_packet函數構造這個答復包然后發送。散列算法的實現在password.c的scramble(char *to, const char *message, const char *password)函數。
四、再度發送scrambled password (可選)
授權信息已經發送過去了,服務器可以會回答說OK(發回一個OK_PACKET),也有可能會要求再度發送scrambled password。
如果要再度發送,服務器會返回一個1字節的包,如果第一個字節是0xFE且mysql.server_capabilities設置了CLIENT_SECURE_CONNECTION,那么
就需要再度發送scrambled password
這個似乎是為了和以前老版本兼容,這次需要使用3.23版的scramble對password進行加密然后發送。
scramble_323(buff, mysql->scramble, passwd);
如:
0x8059000: 0x09 0x00 0x00 0x03 0x4d 0x45 0x46 0x4c
0x8059008: 0x4f 0x44 0x4b 0x4b 0x00
這個包的格式很簡單,包頭,然后是9個字節的scramble(其中最后一個字節必須是0x00)
不過要注意,此處包頭的第4個字節是0x03,因為這是認證過程是雙方來回發送的第三個包了。
五、命令
0x20,0x00,0x00,0x00, 包頭
0x03 //命令的類型,COM_QUERY
select * from xxx where xxx //arg
========================================================
MYSQL認證漏洞:
1、構造0長度的scramble繞過密碼校驗
這幾乎可以算是mysql目前發現的危害性最嚴重的安全漏洞了。
出問題的代碼:
my_boolcheck_scramble_323(constchar*scrambled,constchar*message,ulong*hash_pass){structrand_structrand_st;ulonghash_message[2];charbuff[16],*to,extra;/* Big enough for check */constchar*pos;hash_password(hash_message,message,SCRAMBLE_LENGTH_323);randominit(&rand_st,hash_pass[0]^hash_message[0],hash_pass[1]^hash_message[1]);to=buff;for(pos=scrambled;*pos;pos++)*to++=(char)(floor(my_rnd(&rand_st)*31)+64);extra=(char)(floor(my_rnd(&rand_st)*31));to=buff;while(*scrambled){if(*scrambled++!=(char)(*to++^extra))return1;/* Wrong password *
相關標簽:
本文原創發布php中文網,轉載請注明出處,感謝您的尊重!
總結
以上是生活随笔為你收集整理的mysql 协议说明_MySQL认证协议_MySQL的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tf口红多少钱啊?
- 下一篇: mysql8 mac 忘记密码_mac下