天天看点

MySQL · 源码分析 · mysql认证阶段漫游

client发起一个连接请求, 到拿到server返回的ok包之间, 走三次握手, 交换了[不可告人]的验证信息, 这期间mysql如何完成校验工作?

MySQL · 源码分析 · mysql认证阶段漫游

hash_stage1 = sha1(password)

hash_stage2 = sha1(hash_stage1)

reply = sha1(scramble, hash_stage2) ^ hash_stage1

// 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)是否一致来判定是否合法

如图, client发起连接请求, server创建新的线程, 并进入acl_authenticate(5.7位于sql/auth/sql_authentication.cc, 5.6位于sql/sql_acl.cc)函数完成信息验证, 并把包里读出的信息更新到本线程.

流程堆栈:

接下来考察这些函数中做了哪些事.

check_connection(sql/sql_connect.cc)

当接收到client的建连接请求时, 进入check_connection, 先对连接本身上下文分析(socket, tcp/ip的v4/6 哇之类的)

当然你用very long的host连进来, 也会在这里被cut掉防止overflow.

不合法的ip/host也会在这里直接返回, 如果环境ok, 就进入到acl_authenticate的逻辑中

acl_authenticate:

初始化mpvio_ext, 用于保存验证过程的上下文; 字符集, 挑战码, …的坑位, 上锁, 根据command进行分派, (新建链接为com_connect

com_connect下会进入函数do_auth_once(), 返回值直接决定握手成功与否.

先对authentication plugin做判定, 咱们这里基于”mysql_native_password”的情况

在mysql_native_password时会进入native_password_authenticate 逻辑:

可见这里才生成了挑战码并发送到client, 再调用mpvio->read_packet等待client回包,

进入server_mpvio_read_packet,

这里的实现则调用常见的my_net_read读包,

当拿到auth包时, 逻辑分派到parse_client_handshake_packet, 对包内容进行parse, 这里会根据不同client protocol, 去掉头和尾, 还对client是否设置了ssl做判定. 接着:

在拿到了client发来的加密串(虽然叫passwd), 暂时存放在内存中, 返回native_password_authenticate,

当判定为需要做password check时(万一有人不设置密码呢), 进入check_scramble, 这个函数中才实现了对密码的验证:

native_password_authenticate拿到check_scamble的返回值, 返回ok,

再返回到acl_authenticate, 讲mpvio中环境信息更新到线程信息thd中, successful login~

(所以可以魔改这块代码搞事, 密码什么的, 权限什么的….

(我就说说, 别当真