移动云海山数据库(He3DB)-客户端连接认证

84 阅读4分钟

连接过程概述

MySQL客户端和服务端建立连接的过程可以概括为:

  1. server 监听端口
  2. client 向server建立TCP连接
  3. server 向client发送挑战码报文(mysql认证采用的是CHAP 协议,即挑战握手认证协议,挑战码用于加密client输入的密码,从而避免了网络传输明文密码)
  4. client 使用挑战码加密密码,将加密后的密码包含在回包中,发送给server
  5. server 根据client的回包解密,检查是否与预期的结果相同,给client发送ok包或error包

客户端连接认证流程

其中客户端连接认证流程如下: 从sql_connection.cc下的thd_perpare_connection开始看起。 |-->thd_perpare_connection(权限认证) image.png

……|-->lex_start(在准备和执行每个查询之前调用lex_start(),创建select_lex和select_lex_unit对象) image.png

……|-->login_connection(识别用户,并报告错误) image.png

…………|-->set_read_timeout(设置网络接收的超时时间) …………|-->set_write_timeout(设置网络发送的超时时间) …………|-->check_connection(执行握手、授权客户端并更新thd ACL变量) ………………|-->如果是TCP/IP方式连接: image.png acl_check_host检查host或ip是否匹配 image.png

………………|-->如果是socket方式连接: image.png

设置host,默认为localhost image.png ………………|-->设置为keepalive image.png ………………|-->分配net_buffer_length,为SESSION变量,表示TCP/IP和socket通信缓冲区大小,设定的大一点可以加快导入速度 image.png

………………|-->认证前审计检查 image.png

………………|-->acl_authenticate密码认证 image.png

……………………|-->do_auth_once使用默认插件执行第一次身份验证尝试。 这会发送服务器握手数据包,读取带有用户名的客户端回复,并在每个人都使用了正确的插件时执行身份验证(具体展开见后文) ………………|-->认证后审计检查 image.png

…………|-->发送状态信息到客户端 image.png

…………|-->发送ok包 image.png

……|-->初始化thd,准备处理客户端请求 image.png

acl_authenticate密码认证流程如下: 函数位于sql_authentication.cc下 |-->acl_authenticate ……|-->do_auth_once使用默认插件执行第一次身份验证尝试。 这会发送服务器握手数据包,读取带有用户名的客户端回复,并在每个人都使用了正确的插件时执行身份验证 …………|-->authenticate_user image.png

………………|-->指向native_password_authenticate image.png

……………………|-->generate_user_salt服务端生成挑战码 image.png

……………………|-->write_packet握手认证阶段(客户端与服务器建立连接后进行),服务端发送初始化报文到客户端 image.png …………………………|-->指向server_mpvio_write_packet ………………………………|-->send_server_handshake_packet tips:权能标志:用于与客户端协商通讯方式。客户端收到服务器发来的初始化报文后,会对服务器发送的权能标志进行修改,保留自身所支持的功能,然后将权能标返回给服务器,从而保证服务器与客户端通讯的兼容性。 image.png image.png

……………………………………|-->protocol_classic.cc-->my_net_write发送报文给客户端 image.png ……………………|-->read_packet服务端接收并解析客户端发送的登录认证信息报文 …………………………|-->指向server_mpvio_read_packet ………………………………|-->read_packet读取客户端报文 image.png ……………………………………|-->my_net_read ……………………|-->parse_client_handshake_packet解析客户端报文 image.png …………………………|-->客户端报文格式在client.c-->send_client_replay_packet中 image.png image.png ……………………|-->check_scramble检查密码是否正确。pkt:接收的客户端加密后的密码;scramble:扰乱;salt:该用户加密后的真实密码 image.png …………………………|-->password.c下的check_scramble。scramble_arg:接收的客户端加密后的密码;message:扰乱;hash_stage2:该用户加密后的真实密码

………………………………|-->check_scramble_sha1检查加扰消息是否与密码对应;服务器使用该功能来检查接收到的回复是否真实。 image.png

……………………………………|-->buf=sha1(message,hash_stage2) image.png

……………………………………|-->buf=xor(buf,scramble_arg) image.png

……………………………………|-->hash_stage2_reassured=sha1(buf) image.png

……………………………………|-->比较(hash_stage2,hash_stage2_reassured) image.png

服务端客户端加密解密原理梳理

image.png

客户端

{
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、服务器利用A^B^B=A的原理,得到server_A,如果client_B=real_B的话,那么server_A其实是等于client_A的,也就是说,对server_A做1次hash得到的server_B是等于real_B的