总体交互过程
登录流程
- TCP连接建立
|
|
- Server向Client发送Handshake packet:包含server版本信息, 随机挑战数等
- Client与Server发送Auth packet
- Server向Client发送OK packet或者ERR packet
认证细节
-
CHAP协议
- the server sends the random scramble to the client.
- client sends the encrypted password back to the server.
- the server checks the password.
-
客户端加密
- stage1 = sha1(password)
- crypt = (sha1(scramble + sha1(stage1))) ^ stage1
|
|
-
服务端验证 (基于异或的自反性: A ^ B ^ A = B)
- stage1’ = crypt ^ (sha1(scramble + mysql.user.password))
- sha1(stage1’) == mysql.user.password
注:即使mysql.user.password泄露也无法认证,因为不知道stage1
服务端数据包
- 组成
- head(4 byte)
- payload_length (3 byte)
- sequense_id (1 byte)
- payload
- head(4 byte)
- 最大长度(2 ** 24 - 1),payload等于最大长度时,会拆成多个包,即最后一个包长度总小于最大长度
- head 解析
|
|
注:strucut没有3 byte的类型,故需要分别读H(2 byte)和B(1 byte),然后进行拼接, 小端编码低位在前,所以实际值为 H + B « 16
- 包的种类:
- OK: header = 0 and length of packet > 7
- EOF(deprecated since 5.7.5): header = 0xfe and length of packet < 9
- ERROR: header = 0xff
- Result Set: header in [1, 250]
客户端数据包
- 组成
- head(4 byte)
- payload_length (3 byte)
- sequense_id (1 byte)
- payload
- command(1 byte)
- arguments
- head(4 byte)
|
|
cursor
- Cursor: 默认curosr
- SSCursor: 不预先将结果一次性全部读入缓存中, 适用于获取大数据时
参考
- https://dev.mysql.com/doc/internals/en/sending-more-than-16mbyte.html
- https://www.python.org/dev/peps/pep-0249/#cursor-objects
- https://jin-yang.github.io/post/mysql-protocol.html
- https://www.godpan.me/2017/11/10/mysql-protocol.html
- https://zh.wikipedia.org/wiki/%E9%80%BB%E8%BE%91%E5%BC%82%E6%88%96
- https://zh.wikipedia.org/zh-hans/%E8%AF%A2%E9%97%AE%E6%8F%A1%E6%89%8B%E8%AE%A4%E8%AF%81%E5%8D%8F%E8%AE%AE
- https://cloud.tencent.com/developer/article/1005252
- https://www.callmejiagu.com/2018/11/01/%E5%9F%BA%E4%BA%8EMySQL-Protocol%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%B7%B1%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E9%A9%B1%E5%8A%A8/