当前位置: 首页 > article >正文

55 mysql 的登录认证流程

前言

这里我们来看一下 mysql 的认证的流程 

我们这里仅仅看 我们最常见的一个 认证的处理流程

我们经常会登录的时候 碰到各种异常信息

 

 

认证失败的大体流程

大概的流程是这样 

客户端和服务器建立连接之后, 服务器向客户端发送 salt

然后 客户端根据 salt 将客户端传入的密码加密之后, 以及相关登录信息传递给服务器 

然后 服务器进行验证, 验证失败, 响应对应的错误信息给客户端 

b7f2f81ceff12b4e7dd93170e3ee1aa0.png

 

服务器发送 salt 的信息如下 

3449c1caa4f7b03c71459f6a5a1c378f.png 

客户端发送的认证请求如下 

d78e4f8c3d6f517995695d770fa33880.png

 

 服务器响应的认证失败信息如下 

3c87143a1162269942ef12ed6cb48496.png

 

服务器发送 slat 的信息是在这里, 这里的 salt 是随机生成的 

077e1db2fab82ef6d406988a09fcc33e.png 

读取客户端的加密之后的信息 

c33f23fa6a16a0c2e15e577a3558f018.png 

然后是 密码的验证, 我们这里的流程是这样, 这里 数据库用 root 用户没有密码, 但是客户端这边传入了密码, 因此这里直接响应了 CA_AUTH_USER_REDENTIALS

23fefefbe4a62457a9849bcbbb3bff45.png

  

然后接着是 响应错误信息给客户端, 这里是响应 1045 ACCESS_DENIED_ERROR “Access denied for user 'root'@'192.168.220.1' (using password: YES)”

b5be01b8a38cc7e162af1fa3c3ce50f2.png

 

 

Access denied for user 'root'@'192.168.220.1' (using password: YES) 

这里同上, 几种情况 

首先需要传递密码, 其次是 root用户密码为空 或者 密码不对 会响应如下问题

上面演示了 mysql 密码为空, 但是 我输入了密码 之后的校验情况

我们现在来看一下 密码对不上的情况

用到了一些加密的特性来验证, 客户端输入的密文和数据库是否匹配 

scramble_arg 表示的是客户端传入的密文, message 表示数据库的密文, hash_stage2 表示此次登录验证的 slat 

2ebb889daa7b6b93749ba8d72d96369f.png

 

 

Access denied for user 'root'@'192.168.220.1' (using password: NO) 

这种情况就是 该用户有密码, 但是客户端 未传递 密码

验证是在这里, 如果数据库中该用户也没有密码, 直接 OK, 否则 响应 CR_AUTH_USER_CREDENTIALS

到后面的错误输出环节, 得到的错误信息 就是上面

d078fa1cad2859b912351ce7f33560e7.png

 

 

客户端加密, 服务器验证的逻辑仿写 

这里主要是 实现了一个 客户端这边 传递的密码的加密方式的处理

以及 服务器这边 验证 客户端秘钥, 服务器秘钥 的一个验证方式

可以参考学习一下, 需要导入 mysql-driver, netty 等等相关工具 

salt 是服务器的 ServerGreeting 传递回来的, 是一个 20自己的随机字节序列

clientPwd 是根据用户名, 密码 salt 加密之后的一个结果 

serverPwd 是 mysql 中 mysql.user 库中该用户记录的 authentication_string 秘钥序列

/**
 * Test09MysqlLoginEncrypt
 *
 * @author Jerry.X.He
 * @version 1.0
 * @date 2023/8/9 9:31
 */
public class Test09MysqlLoginEncrypt {

    // Test09MysqlLoginEncrypt
    public static void main(String[] args) throws Exception {

        String salt = ("2c 4f 04 2a 30 13 69 71").replaceAll("\\s+", "")
                + ("03 17 0a 1d 64 55 7e 68 1f 19 73 0a").replaceAll("\\s+", "");
        String clientPwd = "012cb36acb2a4c77217d8d70dc43e058c1c6448a";
        String serverPwd = "81F5E21E35407D884A6CD4A731AEBFB6AF209E1B";

        String clientPwdEncoded = ByteBufUtil.hexDump(clientEncryptPwd("root", "root", salt));
        boolean clientPwdIfMatch = checkClientPwdIfMatch(clientPwd, salt, serverPwd);
        AssertUtils.assert0(clientPwd, clientPwdEncoded, " check if clientEncryptPwd match ");
        AssertUtils.assert0(clientPwdIfMatch, " checkClientPwdIfMatch match ");
        int x = 0;

    }

    /**
     * checkClientPwdIfMatch
     *
     * @return boolean
     * @author Jerry.X.He
     * @date 2023/8/9 10:31
     */
    public static boolean checkClientPwdIfMatch(String clientPwd, String salt, String serverPwd) {
        byte[] saltBytes = ByteBufUtil.decodeHexDump(salt);
        byte[] pwdInClient = ByteBufUtil.decodeHexDump(clientPwd);
        byte[] pwdInDb = ByteBufUtil.decodeHexDump(serverPwd);

        MessageDigest digest = DigestUtils.getSha1Digest();
        digest.reset();
        digest.update(saltBytes);
        digest.update(pwdInDb);
        byte[] pwdSaltUpdated = digest.digest();

        my_crypt(pwdSaltUpdated, pwdSaltUpdated, pwdInClient);

        digest.reset();
        digest.update(pwdSaltUpdated);
        byte[] pwdFinalUpdated = digest.digest();

        boolean clientPwdEqualsDb = ByteBufUtil.hexDump(pwdFinalUpdated).equalsIgnoreCase(serverPwd);
        return clientPwdEqualsDb;
    }

    /**
     * clientEncryptPwd
     *
     * @return byte[]
     * @author Jerry.X.He
     * @date 2023/8/9 10:22
     */
    public static byte[] clientEncryptPwd(String username, String password, String salt) {
        MysqlNativePasswordPlugin plugin = new MysqlNativePasswordPlugin();
        NativeProtocol protocol = new MyNativeProtocol(new NullLogger(""));
        plugin.init(protocol);
        NativePacketPayload fromServer = new NativePacketPayload(ByteBufUtil.decodeHexDump(salt));
        List<NativePacketPayload> toSaveList = new ArrayList<>();
        plugin.setAuthenticationParameters(username, password);
        plugin.nextAuthenticationStep(fromServer, toSaveList);
        return toSaveList.get(0).getByteBuffer();
    }

    /**
     * my_crypt
     *
     * @return void
     * @author Jerry.X.He
     * @date 2023/8/9 10:21
     */
    public static void my_crypt(byte[] to, byte[] s1, byte[] s2) {
        for (int i = 0; i < s1.length; i++) {
            to[i] = (byte) (s1[i] ^ s2[i]);
        }
    }

    /**
     * Test09MysqlLoginEncrypt
     *
     * @author Jerry.X.He
     * @version 1.0
     * @date 2023/8/9 10:19
     */
    private static class MyNativeProtocol extends NativeProtocol {
        public MyNativeProtocol(Log logger) {
            super(logger);
        }

        @Override
        public String getPasswordCharacterEncoding() {
            return "UTF-8";
        }
    }

}

 

运行处理, 信息如下 

8decf59dbd830698990ae6a8e1658f78.png

 

 

完 

 

 

 


http://www.kler.cn/news/310661.html

相关文章:

  • 掌握MATLAB中的数据类型转换技巧
  • 21. 什么是MyBatis中的N+1问题?如何解决?
  • qt信号与槽(自定义)
  • 手势识别-Yolov5模型-自制数据集训练
  • Kafka是如何保证数据的安全性、可靠性和分区的
  • 共享股东分红模式小程序开发
  • [数据集][目标检测]葡萄成熟度检测数据集VOC+YOLO格式1123张3类别
  • C HTML格式解析与生成之gumbo
  • python怎么输入整数
  • 万能小程序运营管理系统 _requestPost 任意文件读取漏洞复现
  • DAY20240911 VUE:解锁前端路由的奥秘:如何在单页应用中避免404困境?
  • 流量牵引技术与传统防火墙的区别
  • 在网络环境中怎么保护个人信息安全?
  • 土壤墒情测定仪的工作原理
  • 汽车软件开发之敏捷开发
  • Spring 源码解读:手动实现Spring事件机制
  • JSON.parseArray 内存溢出
  • 【第十一章:Sentosa_DSML社区版-机器学习分类】
  • Oracle数据库高级技术探秘:分区表管理与代码实战
  • Python 全栈系列271 微服务踩坑记
  • 数据库学习02——mysql清空表数据后 IBD 文件仍很大的解决方案
  • 面向开发者的LLM入门教程(学习笔记01)
  • 探索学习Python的最佳开发环境和编辑器
  • 家用燃气报警器-家庭可燃气体探测器-旭华智能
  • 【网络安全】服务基础第二阶段——第四节:Linux系统管理基础----Linux网络与日志服务器
  • Docker 镜像制作(Dockerfile)
  • 为解决bypy大文件上传报错—获取百度云文件直链并使用Aria2上传文件至服务器
  • Mini-Omni:语言模型可以在流中听、说和思考
  • Docker本地部署Chatbot Ollama搭建AI聊天机器人并实现远程交互
  • Spring boot aop集成(面向切面的编程)