Skip to content

Commit

Permalink
update sql docs
Browse files Browse the repository at this point in the history
  • Loading branch information
fengzhao committed Oct 30, 2024
1 parent 64d42eb commit b94f91c
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 5 deletions.
66 changes: 61 additions & 5 deletions docs/foundmental/1.MySQL协议分析与抓包概述.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
- 我的这条数据不知道被谁改了,能帮我查一下吗?

- 能帮我查查这张表都有谁在访问吗?
昨天某个时间监控有个尖刺,能帮忙看看执行了哪些 SQL 吗?
某一个 SQL 语句中有手机号、身份证号,或者密码明文等敏感信息,这个语句是谁在执行?
某一张表中存储了手机号、密码等明文信息,又是谁在读写这张表呢?

- 昨天某个时间监控有个尖刺,能帮忙看看执行了哪些 SQL 吗?

- 某一个 SQL 语句中有手机号、身份证号,或者密码明文等敏感信息,这个语句是谁在执行?

- 某一张表中存储了手机号、密码等明文信息,又是谁在读写这张表呢?

面对这些问题,我们会想方设法去找找慢日志,或者查询日志,甚至分析 binlog ,运气好的话可以找到一些线索,但大多数时候都不尽人意。详细的访问信息,带用户名、客户端 IP 的只有慢日志会记录,生产环境又不可能把所有 SQL 都记录下来,那会极大的拖慢系统性能,甚至有几率会带来故障,因此这成为了一个让 DBA 头疼的问题。

Expand All @@ -24,7 +27,7 @@

- General log:这种方案可以记录所有访问日志,但日志内容匮乏,只包括了 Query 语句,而缺少了访问 IP ,用户名等信息,并且如果线上都打开这个日志文件,对 MySQL 性能的冲击很大,容易产生故障,所以很难实现我们的需求。

- Slow log:将 long_query_time 参数设置为 0 ,即可记录所有 MySQL Server 端执行的 SQL 语句,用户名、客户端 IP 、执行时间等信息均有记录,但是带来的问题与开启 General log 相同,生产环境不可能一直开启。
- Slow log:将 long_query_time 参数设置为 0 ,即可记录所有 MySQL Server 端执行的 SQL 语句,用户名、客户端 IP 、执行时间等信息均有记录,但是带来的问题与开启 General log 相同,生产环境不可能一直开启。

- Audit plugin:使用 MySQL 自带的审计功能,其实是可以实现部分需求的,但问题点在于 audit 本身是 MySQL 的一个插件,与版本关系比较大,功能不尽相同,而最大的一个问题是,如果开启这个插件功能,需要重启数据库,这是比较要命的,所以也不能被采用。

Expand Down Expand Up @@ -52,6 +55,21 @@
本文不讨论语言层, 主要阐述 `MySQL Client/Server` 的通信协议, 了解了整个通信协议之后, 无论是针对什么编程语言, 哪怕是自己开发的新编程语言, 也都可以自行实现一个 MySQL 驱动, 基于 MySQL 驱动可以在上层做更多自定义的事情。例如实现 MySQL 数据到 Redis、ElasticSearch、MongoDB 等的数据同步、开发 MySQL Proxy 等。


MySQL客户端与服务器的交互主要分为两个阶段:握手认证阶段和命令执行阶段。

握手认证阶段

握手认证阶段为客户端与服务器建立连接后进行,交互过程如下:

服务器 -> 客户端:握手初始化消息
客户端 -> 服务器:登陆认证消息
服务器 -> 客户端:认证结果消息

命令执行阶段
客户端认证成功后,会进入命令执行阶段,交互过程如下:

客户端 -> 服务器:执行命令消息
服务器 -> 客户端:命令执行结果


MySQL通信协议是一个有状态的协议,主要用于MySQL客户端与服务器之间的通信。这个协议在MySQL客户端连接器(如Connector/C、Connector/J等)、MySQL Proxy以及主从复制中都有实现。
Expand Down Expand Up @@ -131,6 +149,10 @@ mysql客户端和服务器之间的通信怎么实现?协议特征有哪些?
- Client——>Server,Login Request,Client发起的登录请求报文,


#### TCP三次握手


#### 挑战数据包

MySQL采用的是挑战-响应方式来进行身份认证。由服务端生成加密用的盐给客户端,提高安全性。

Expand All @@ -140,7 +162,7 @@ MySQL采用的是挑战-响应方式来进行身份认证。由服务端生成

| 名称 | 类型 | 长度 | 含义 |
| ---------------------------- | ------ | ------ | ------------------------------------------------------------ |
| Protocol | int | 1 byte | MySQL应用协议的版本号 |
| Protocol | int | 1 byte | MySQL应用协议的版本号,参考MySQL源代码/include/mysql_version.h头文件定义 |
| Version | string | 不确定 | MySQL Server的版本号 |
| Thread ID | int | 4 byte | 建立连接所分配的线程id |
| Salt | | | 挑战字符串,相当于用于加密密码的盐,分为两部分,长度分别为8字节和12字节 |
Expand All @@ -155,5 +177,39 @@ MySQL采用的是挑战-响应方式来进行身份认证。由服务端生成



#### 认证数据包



#### 切换加密算法

如果挑战数据包返回的`Authentication Plugin`认证插件与你的用户密码加密方式不一致(比如你的用户采用的是`mysql_native_password`加密,而服务器返回的是`caching_sha2_password`),那么校验肯定失败,所以需要更换加密方式。服务器会发送一个切换认证插件请求数据包来指示客户端重新加密密码并发送。




#### 成功响应报文


![alt text](./response_ok.png)

Response OK ,成功响应,这个没什么好说的。


#### 密码插件算法


MySQL 5.6/5.7 的默认密码插件一直以来都是 `mysql_native_password`。其优点是它支持 `challenge-response` 机制,这是非常快的验证机制,无需在网络中发送实际密码,并且不需要加密的连接。

然而,`mysql_native_password` 依赖于 SHA1 算法,但 NIST(美国国家标准与技术研究院)已建议停止使用 SHA1 算法,因为 SHA1 和其他哈希算法(例如 MD5)已被证明非常容易破解。



此外,由于 `mysql_native_password` 在 mysql.user 表中 `authentication_string` 字段存储的是两次哈希 SHA1(SHA1(password)) 计算的值 ,也就是说如果两个用户帐户使用相同的密码,那么经过 `mysql_native_password` 转换后在 mysql.user 表得到的哈希值相同。

尽管有 hash 值也无法得到实际密码信息,但它仍然告诉这两个用户使用了相同的密码。为了避免这种情况,应该给密码加盐(salt),salt 基本上是被用作输入,用于转换用户密码的加密散列函数。由于 salt 是随机的,即使两个用户使用相同的密码,转换后的最终结果将发生较大的变化。


从 MySQL 5.6 开始支持 `sha256_password` 认证插件。它使用一个加盐密码(salted password)进行多轮 SHA256 哈希(数千轮哈希,暴力破解更难),以确保哈希值转换更安全。然而,它需要要么在安全连接或密码使用 RSA 秘钥对加密。所以,虽然密码的安全性更强,但安全连接和多轮 hash 转换需要在认证过程中的时间更长。


Binary file added docs/foundmental/response_ok.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b94f91c

Please sign in to comment.