谈谈java的mysql驱动中NonRegisteringDriver.connect(String url, Properties info)方法的bug

最近在前端同学的推荐下,尝试了一个做 API 前后端解耦的开源项目(开源项目连接:https://github.com/TommyLemon/APIAuto)。

问题发现:部署demo的过程中,发现了java的mysql驱动的bug,jar包版本:8.0.16。

问题剖析:

  1、发现项目在启动连接db的时候一直报认证失败(Access denied for user 'customercentor'@'10.63.66.144' (using password: YES)),确认了数据库连接信息,其他项目是可以连接成功的,说明是工程有问题。

  2、debug工程,发现项目里用的是NonRegisteringDriver.connect(String url, Properties info)方法,其中把用户名和密码以参数的形式放在了url中,参数对象info为空。

   jdbc:mysql://localhost:3306/cutest?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&user=test&password=Cust23mtER_56#

  3、继续追踪,发现mysql驱动是支持这种写法的,如下图,在解析连接信息的时候,它会首先去info中试图获得连接信息,当获得为null的时候,就会调用自己的下面的代码试图从url中解析出需要的连接认证信息(ip、端口、用户名、密码)

   4、继续debug,发现他底层使用了java的java.util.regex.Matcher类,其中设置了正则表达式模板:

private static final Pattern CONNECTION_STRING_PTRN = Pattern.compile("(?<scheme>[\w:%]+)\s*(?://(?<authority>[^/?#]*))?\s*(?:/(?!\s*/)(?<path>[^?#]*))?(?:\?(?!\s*\?)(?<query>[^#]*))?(?:\s*#(?<fragment>.*))?");

  如上图,问题就出现在密码解析的这里,在解析密码的时候,它使用了   (?<query>[^#]*))  导致如果密码带有#号,就会解析错误,我的密码是Cust23mtER_56# ,解析之后变成了Cust23mtER_56,(又测试了密码是Custo_1234#@ 解析之后变成了Custo_1234)所以连接数据库的时候会报认证失败,因为密码确实错了!!!!

  综上,这就是为什么你百度搜索“java Access denied for user 'customercentor'@'10.63.66.144' (using password: YES)”的时候会找到博文说在获得mysql数据库连接的时候,不要把用户名和密码以参数的形式&到url的后面了。

https://blog.csdn.net/lvhaoguang0/article/details/80868821

原文地址:https://www.cnblogs.com/tianhaichao/p/14074145.html