client發起一個連線請求, 到拿到server返回的ok包之間, 走三次握手, 交換了[不可告人]的驗證資訊, 這期間mysql如何完成校驗工作?
hash_stage1 = sha1(password) hash_stage2 = sha1(hash_stage1) reply = sha1(scramble, hash_stage2) ^ hash_stage1複製程式碼
server: (邏輯位於sql/password.c:check_scramble_sha1中, 下文亦有提及)
// mysql.user表中, 對應user的passwd實際上是hash_stage2 res1 = sha1(scramble, hash_stage2) hash_stage1 = reply ^
res1 hash_stage2_reassured = sha1(hash_stage1) 再根據hash_stage2_reassured == hash_stage2(from mysql.user)是否一致來判定是否合法複製程式碼
#0 parse_client_handshake_packet
#1 server_mpvio_read_packet
#2 native_password_authenticate
#3 do_auth_once
#4 acl_authenticate
#5 check_connection
#6 login_connection
#7 thd_prepare_connection
#8 do_handle_one_connection 複製程式碼
if (plugin)
{
st_mysql_auth *auth= (st_mysql_auth *) plugin_decl(plugin)->info;
res= auth->authenticate_user(mpvio, &mpvio->auth_info);
...複製程式碼
在mysql_native_password時會進入native_password_authenticate 邏輯:
/* generate the scramble, or reuse the old one */ if (mpvio->scramble[SCRAMBLE_LENGTH])
create_random_string(mpvio->scramble, SCRAMBLE_LENGTH, mpvio->rand);
/* send it to the client */ if (mpvio->write_packet(mpvio, (uchar*) mpvio->scramble, SCRAMBLE_LENGTH + 1))
DBUG_RETURN(CR_AUTH_HANDSHAKE);
/* read the reply with the encrypted password */ if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
DBUG_RETURN(CR_AUTH_HANDSHAKE);
DBUG_PRINT("info", ("reply read : pkt_len=%d", pkt_len));複製程式碼
if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
{
/*
Get the password field.
*/
passwd= get_length_encoded_string(&end, &bytes_remaining_in_packet,
&passwd_len);
}
else
{
/*
Old passwords are zero terminatedtrings.
*/
passwd= get_string(&end, &bytes_remaining_in_packet, &passwd_len);
}
...複製程式碼
// server decode回包中的加密資訊 // 把上面提到的三個公式包在函式中 my_bool
check_scramble_sha1(const uchar *scramble_arg, const char *message,
const uint8 *hash_stage2) {
uint8 buf[SHA1_HASH_SIZE];
uint8 hash_stage2_reassured[SHA1_HASH_SIZE];
/* create key to encrypt scramble */
compute_sha1_hash_multi(buf, message, SCRAMBLE_LENGTH,
(const char *) hash_stage2, SHA1_HASH_SIZE);
/* encrypt scramble */
my_crypt((char *) buf, buf, scramble_arg, SCRAMBLE_LENGTH);
/* now buf supposedly contains hash_stage1: so we can get hash_stage2 */
compute_sha1_hash(hash_stage2_reassured, (const char *) buf, SHA1_HASH_SIZE);
return MY_TEST(memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE));
}複製程式碼