赞
踩
MySQL客户端和服务端建立连接的过程可以概括为:
其中客户端连接认证流程如下:
从sql_connection.cc下的thd_perpare_connection开始看起。
|–>thd_perpare_connection(权限认证)
……|–>lex_start(在准备和执行每个查询之前调用lex_start(),创建select_lex和select_lex_unit对象)
……|–>login_connection(识别用户,并报告错误)
…………|–>set_read_timeout(设置网络接收的超时时间)
…………|–>set_write_timeout(设置网络发送的超时时间)
…………|–>check_connection(执行握手、授权客户端并更新thd ACL变量)
………………|–>如果是TCP/IP方式连接:
acl_check_host检查host或ip是否匹配
………………|–>如果是socket方式连接:
设置host,默认为localhost
………………|–>设置为keepalive
………………|–>分配net_buffer_length,为SESSION变量,表示TCP/IP和socket通信缓冲区大小,设定的大一点可以加快导入速度
………………|–>认证前审计检查
………………|–>acl_authenticate密码认证
……………………|–>do_auth_once使用默认插件执行第一次身份验证尝试。
这会发送服务器握手数据包,读取带有用户名的客户端回复,并在每个人都使用了正确的插件时执行身份验证(具体展开见后文)
………………|–>认证后审计检查
…………|–>发送状态信息到客户端
…………|–>发送ok包
……|–>初始化thd,准备处理客户端请求
acl_authenticate密码认证流程如下:
函数位于sql_authentication.cc下
|–>acl_authenticate
……|–>do_auth_once使用默认插件执行第一次身份验证尝试。
这会发送服务器握手数据包,读取带有用户名的客户端回复,并在每个人都使用了正确的插件时执行身份验证
…………|–>authenticate_user
………………|–>指向native_password_authenticate
……………………|–>generate_user_salt服务端生成挑战码
……………………|–>write_packet握手认证阶段(客户端与服务器建立连接后进行),服务端发送初始化报文到客户端
…………………………|–>指向server_mpvio_write_packet
………………………………|–>send_server_handshake_packet
tips:权能标志:用于与客户端协商通讯方式。客户端收到服务器发来的初始化报文后,会对服务器发送的权能标志进行修改,保留自身所支持的功能,然后将权能标返回给服务器,从而保证服务器与客户端通讯的兼容性。
……………………………………|–>protocol_classic.cc–>my_net_write发送报文给客户端
……………………|–>read_packet服务端接收并解析客户端发送的登录认证信息报文
…………………………|–>指向server_mpvio_read_packet
………………………………|–>read_packet读取客户端报文
……………………………………|–>my_net_read
……………………|–>parse_client_handshake_packet解析客户端报文
…………………………|–>客户端报文格式在client.c–>send_client_replay_packet中
……………………|–>check_scramble检查密码是否正确。pkt:接收的客户端加密后的密码;scramble:扰乱;salt:该用户加密后的真实密码
…………………………|–>password.c下的check_scramble。scramble_arg:接收的客户端加密后的密码;message:扰乱;hash_stage2:该用户加密后的真实密码
………………………………|–>check_scramble_sha1检查加扰消息是否与密码对应;服务器使用该功能来检查接收到的回复是否真实。
……………………………………|–>buf=sha1(message,hash_stage2)
……………………………………|–>buf=xor(buf,scramble_arg)
……………………………………|–>hash_stage2_reassured=sha1(buf)
……………………………………|–>比较(hash_stage2,hash_stage2_reassured)
客户端
{
recv(scramble)
client_A=sha1(password)
client_B=sha1(client_A)
C=xor(client_A,sha1(scramble,client_B))
}
服务端
{
recv(C)
server_A = xor(C,sha1(scramble,real_B))
备注:real_B=sha1(sha1(real_password))
server_B=sha1(server_A)
memcmp(real_B,server_B)
}
即:
1、客户端对密码做2次hash,在加上扰乱、异或得到C,把C发送给服务器
2、服务器利用ABB=A的原理,得到server_A,如果client_B=real_B的话,那么server_A其实是等于client_A的,也就是说,对server_A做1次hash得到的server_B是等于real_B的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。