抓包工具采用的是Wireshark,mysql客户端使用的是java操作jdbc连接mysql。
mysql采用的是挑战-响应方式来进行身份认证。由服务端生成加密用的盐给客户端,提高安全性
数据包携带的信息如下:
名称 | 类型 | 长度 | 描述 |
---|---|---|---|
Protocol | int | 1个字节 | 协议的版本号 |
Version | string | 不确定 | mysql的版本 |
Thread ID | int | 4个字节 | 建立连接所分配的id |
Salt | string | 20个字节 8+12 | 挑战字符串,相当于用于加密密码的盐,分为两部分,长度分别为8字节和12字节 |
Server Capabilities | int | 2个字节 | 服务器支持的功能,int为32位,1支持,0不支持,最多支持32种功能。这里占2个字节,为int的前16位 |
Server Language | int | 1个字节 | 服务器编码,通常为utf8mb4 |
Server Status | int | 2个字节 | 服务器状态,通常为SERVER_STATUS_AUTOCOMMIT,表示自动提交事务 |
Extended Server Capabilities | int | 2个字节 | 服务器支持的拓展功能,int为32位,1支持,0不支持,最多支持32种功能。这里占2个字节,为int的后16位 |
Authentication Plugin Length | int | 1个字节 | ?好像指的是挑战字符串的长度,没搞懂为什么是21而不是20 |
Unused | 10个字节 | 未使用的部分 | |
Authentication Plugin | string | 不确定 | 密码采用的加密方法,通常为mysql_native_password |
接收到服务端的挑战数据包后,客户端需要发送认证信息给服务端用于校验
数据包携带的信息如下:
名称 | 类型 | 长度 | 描述 |
---|---|---|---|
Client Capabilities | int | 2个字节 | 客户端支持的功能,类似Server Capabilities |
Extended Client Capabilities | int | 2个字节 | 客户端支持的拓展功能,类似客户端支持的功能,类似Extended Server Capabilities |
MAX Packet | int | 4个字节 | 最大的数据包大小 |
Charset | int | 1个字节 | 客户端编码 |
Unused | 23个字节 | 未使用的部分 | |
Username | string | 不确定 | 登录的用户名 |
Password | string | 不确定 | 登录的密码,已加密 |
Schema | string | 不确定 | 连接的库 |
Client Auth Plugin | string | 不确定 | 认证使用的插件,即采用的哪种密码加密算法 |
Connection Attributes | 不确定 | 客户端的相关参数,键值对的形式。包括客户端版本、客户端名称等 |
如果挑战数据包返回的Authentication Plugin认证插件与你的用户密码加密方式不一致(比如你的用户采用的是mysql_native_password加密,而服务器返回的是caching_sha2_password),那么校验肯定失败,所以需要更换加密方式。服务器会发送一个切换认证插件请求数据包来指示客户端重新加密密码并发送。
数据包携带的信息如下:
名称 | 类型 | 长度 | 描述 |
---|---|---|---|
Response Code | int | 1个字节 | 响应状态码 0xfe表示结果集结束 |
Auth Method Name | string | 不确定 | 要切换的认证插件 |
Auth Method Data | string | 20个字节 | 挑战数据,盐,用于重新加密 |
客户端采用新的加密算法后,将密码再发送给服务端
数据包携带的信息如下:
名称 | 类型 | 长度 | 描述 |
---|---|---|---|
Auth Method Data | string | 20个字节 | 采用新的认证插件加密后的密码 |
数据包携带的信息如下:
名称 | 类型 | 长度 | 描述 |
---|---|---|---|
Response Code | int | 1个字节 | 响应状态码,0x00代表操作成功 |
Affected Rows | int | 不确定 | 影响的行数,通常在操作数据时才有值 |
Server Status | int | 2个字节 | 服务器状态,0x0002代表自动提交 |
warnings | int | 2个字节 | 服务器产生的警告次数 |
测试:使用错误的密码连接MySQL
数据包携带的信息如下:
名称 | 类型 | 长度 | 描述 |
---|---|---|---|
Response Code | int | 1个字节 | 响应状态码,0xff代表操作失败 |
Error Code | int | 2个字节 | 错误码,1045表示访问被拒绝 |
SQL state | string | 5个字节 | sql状态,28000表示认证失败 |
Error message | string | 不确定 | 错误提示信息 |
如果连接参数使用了SSL(useSSL=true),认证将会使用TLS/SSL对数据进行加密,客户端和服务端后续都会采用TSL数据包来进行数据发送
如果挑战数据包返回的密码加密方法与用户的密码加密方法不匹配,那么认证不会直接成功,服务端会发送一个Auth Switch Request数据包(指定了应该使用哪种加密算法)来提醒用户更改加密算法,用户则发送一个Auth Switch Response数据包来发送重新加密后的密码。
常用的加密方法有caching_sha2_password和mysql_native_password。通过修改mysql默认的认证插件可以指定挑战数据包返回的密码加密方式default_authentication_plugin=mysql_native_password
public static void main(String[] args) throws SQLException {
Connection c = DriverManager.getConnection("jdbc:mysql://192.168.86.111:3306/test?useSSL=false", "root", "123456");
Statement s = c.createStatement();
ResultSet rs = s.executeQuery("show variables like 'datadir'");
if (rs.next())
System.out.println(rs.getString(2));
}