mysql 协议说明_MySQL认证协议_MySQL
本文是針對MySQL 5.5.9寫的。MySQL協(xié)議是向老版本兼容的。老版本的MySQL Client可能不理解下面的某些字段而忽略掉。
實際使用的時候,服務器的協(xié)議版本應當大于等于客戶端。遺憾的是,MySQL并沒有對每一次協(xié)議變動標一個數(shù)字。
本文中所說的”字節(jié)”一詞,英文是Byte。遵循C語言中定義,即char的大小。注意:沒有規(guī)定1字節(jié)一定等于8位。所以如果你準備在1字節(jié)不等于8位的環(huán)境中使用mysql,那是給自己找事。
我祈禱你的char是有符號的。
參考http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol(我也參與這個頁面的編輯)
一、客戶端連接服務器的流程
請參見sql-common/client.c的CLI_MYSQL_REAL_CONNECT函數(shù)。使用系統(tǒng)的socket函數(shù)建立一個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);
然后設置各種參數(shù)
客戶端接下來的流程可分為三個階段: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函數(shù)建立socket,然后bind。服務器專門有一個線程(可稱為Connection Manager)處理新來的網(wǎng)絡連接。這個線程的主函數(shù)是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線程的入口函數(shù)是在sql/sql_connect.cc中的handle_one_connection。sql/sql_parse.cc的do_command從網(wǎng)絡連接上讀一個command,并執(zhí)行。handle_one_connection函數(shù)是以while循環(huán)的方式執(zhí)行do_command。
三、協(xié)議
客戶端發(fā)給服務器的包可分為兩種:登錄時的一個auth包,以及身份驗證結(jié)束后的command包。
服務器發(fā)給客戶端的包可分為四種:登錄時的握手包、數(shù)據(jù)包、數(shù)據(jù)流結(jié)束包、成功包(OK Packet)、錯誤信息包。
所有的包都具有統(tǒng)一的格式,由統(tǒng)一的函數(shù)(sql/net_serv.cc:my_net_write(…))寫入buffer等待發(fā)送。長度描述
3包長度(單位:字節(jié))。按低字節(jié)低址的規(guī)則存放。因為一共就3個字節(jié),所以單個包的最大長度是(2的16次方-1)字節(jié),約等于16MB。最小長度是0。
1序號。第一個是0。
ndata。
實際上,包長等于 2的16次方-1的包也會被拆成2個包發(fā)送。因為Mysql最初沒有考慮突破16M,也沒有預留任何字段做標志這個包的數(shù)據(jù)不完整。所以只好把長度為2的16次方-1的包視做不完整的包,直到后面收到一個長度小于2的16次方-1的包,然后拼起來。所以最后一個包的長度有可能是0。
登錄
服務器在每收到一個新的連接的時候,會使用sql/sql_connect.cc的login_connection函數(shù)作身份驗證。先根據(jù)IP做acl,然后才進入用戶名密碼驗證階段。mysql的登錄協(xié)議是經(jīng)典的CHAP協(xié)議,sql/sql_acl.cc的native_password_authenticate函數(shù)的注釋簡單了解釋了這個協(xié)議: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字節(jié)整數(shù),在4.1以及后續(xù)版本是20字節(jié)整數(shù)。它是由password.c的create_random_string函數(shù)生的,因為它采用的是rand()%94+33這樣的方式生的,所以scramble的每個字節(jié)一定是[33,127)之間的ASCII字符,在協(xié)議中發(fā)送時,是加上’/0’之后發(fā)的(這個后面會詳細解釋)。
命令—答復
在身份驗證之后,服務器和客戶端之間處于一問一答的模式。 截至到Mysql 5.5.9,mysql server一共支持30種command,sql/sql_parse.cc的 dispatch_command函數(shù)寫了一個大大的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
四、服務器的握手包
客戶端執(zhí)行recv,會收到一個來自server的包,其中第一個字節(jié)是協(xié)議的版本號。其它的重要信息還有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函數(shù)的注釋)長度說明
1協(xié)議的版本號 (0x0A)
n以0結(jié)尾的字符串。描述服務器版本
4thread id
8scramble的前8個字節(jié)
10x00。也就是說讓scramble看起來是一個以0結(jié)尾的字符串
2server capabilities的低兩個字節(jié)。
1server character set
2server status
2server capabilities的高兩個字節(jié)。
1scramble的總長度
10保留。必須以0填充。
n(至少12)scramble的剩余部分。(不包含’/0’)
10x00。也就是說讓scramble看起來是一個以0結(jié)尾的字符串
server capabilities表:名字從右往左數(shù)第幾位說明
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
五、然后客戶端將密碼等發(fā)送過去
客戶端根據(jù)服務器發(fā)給的scramble對原始密碼進行散列,然后和其它參數(shù)一起發(fā)給服務器
發(fā)送登錄數(shù)據(jù):
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結(jié)尾的字符串
nhash過的密碼。length (1 byte) coded
ndatabase name,以0結(jié)尾的字符串。只有client capabilities中有CLIENT_CONNECT_WITH_DB時,此字段才有效。
nclient auth plugin name。以0結(jié)尾的字符串。只有client capabilities中有CLIENT_PLUGIN_AUTH時,此字段才有效。如果使用mysql默認的auth機制,此處應該為mysql_native_password
sql-common/client.c的send_client_reply_packet函數(shù)構(gòu)造這個答復包然后發(fā)送。散列算法的實現(xiàn)在password.c的scramble(char *to, const char *message, const char *password)函數(shù)。
四、再度發(fā)送scrambled password (可選)
授權(quán)信息已經(jīng)發(fā)送過去了,服務器可以會回答說OK(發(fā)回一個OK_PACKET),也有可能會要求再度發(fā)送scrambled password。
如果要再度發(fā)送,服務器會返回一個1字節(jié)的包,如果第一個字節(jié)是0xFE且mysql.server_capabilities設置了CLIENT_SECURE_CONNECTION,那么
就需要再度發(fā)送scrambled password
這個似乎是為了和以前老版本兼容,這次需要使用3.23版的scramble對password進行加密然后發(fā)送。
scramble_323(buff, mysql->scramble, passwd);
如:
0x8059000: 0x09 0x00 0x00 0x03 0x4d 0x45 0x46 0x4c
0x8059008: 0x4f 0x44 0x4b 0x4b 0x00
這個包的格式很簡單,包頭,然后是9個字節(jié)的scramble(其中最后一個字節(jié)必須是0x00)
不過要注意,此處包頭的第4個字節(jié)是0x03,因為這是認證過程是雙方來回發(fā)送的第三個包了。
五、命令
0x20,0x00,0x00,0x00, 包頭
0x03 //命令的類型,COM_QUERY
select * from xxx where xxx //arg
========================================================
MYSQL認證漏洞:
1、構(gòu)造0長度的scramble繞過密碼校驗
這幾乎可以算是mysql目前發(fā)現(xiàn)的危害性最嚴重的安全漏洞了。
出問題的代碼:
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 *
相關標簽:
本文原創(chuàng)發(fā)布php中文網(wǎng),轉(zhuǎn)載請注明出處,感謝您的尊重!
總結(jié)
以上是生活随笔為你收集整理的mysql 协议说明_MySQL认证协议_MySQL的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tf口红多少钱啊?
- 下一篇: mysql8 mac 忘记密码_mac下