作者:王祥
爱可生 DBA 团队成员,主要负责 MySQL 故障处理和性能优化。对技术执着,为客户负责。
本文来源:原创投稿
*爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
背景
最近在使用脚本新建了一批应用用户,发现一个奇怪的问题,有部分用户存下以下问题:应用使用该密码能正常访问,但使用 mysql 客户端登录手动输入密码无法登录。经过与正常用户对比发现存在登录异常的用户使用了特殊字符”$”。
问题复现
在测试环境使用脚本生成一批用户
#新建用户脚本简化后如下 #!/bin/bash pw="abc$2UY" mysql --login-path=root -e"create user app@'%' identified by '$pw'" mysql --login-path=root -e"grant insert,update,delete,select on *.* to app@'%'" #测试使用mysql客户端登录 [root@node3 ~]# mysql -h127.0.0.1 -uapp -p #手动输入密码无法登录 Enter password: ERROR 1045 (28000): Access denied for user 'app'@'127.0.0.1' (using password: YES) [root@node3 ~]# mysql -h127.0.0.1 -uapp -p'abc$2UY' #使用单引号无法登录 mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user 'app'@'127.0.0.1' (using password: YES) [root@node3 ~]# mysql -h127.0.0.1 -uapp -pabc$2UY #不加单引号或使用双引号都可以登录 mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 15389 Server version: 8.0.18 MySQL Community Server - GPL Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
问题分析
正常的话上述登录方式都是可以正常登录数据库的,那为什么部分可以部分不可以呢?首先可以确认一下存入数据库的密码是否正确。我们可以手动新建一个用户密码与 app 用户密码保持一致。然后比较 mysql.user 表中 authentication_string 字段是否一致。
mysql> create user test@'%' identified by 'abc$2UY'; Query OK, 0 rows affected (0.05 sec) mysql> select user,host,authentication_string from mysql.user where user in ('app','test'); +------+------+-------------------------------------------+ | user | host | authentication_string | +------+------+-------------------------------------------+ | app | % | *06E0B7BA0149152EE2A387A144A2DF9ACC492297 | | test | % | *7258A15F121DD9F6F7C40C08D34A3DB5ED8C8CB5 | +------+------+-------------------------------------------+
通过对比 authentication_string 字段发现两个密码不一致,说明脚本生成的用户密码并不是原来的密码了。为什么会这样呢?我们知道在 shell 中使用单引号与双引号定义的字符串是有区别的。如下:
[root@node3 ~]# echo "abc$2UY" abcUY [root@node3 ~]# echo 'abc$2UY' abc$2UY [root@node3 ~]# echo abc$2UY abcUY
单引号定义字符串所见即所得,双引号引用的内容,所见非所得。如果内容中有命令、变量等,会先把变量、命令解析出结果,然后再输出最终内容。分析到这回头看脚本密码使用了双引号导致了 $2 被解析成了空,最终存入数据库的密码为:abcUY 。使用 mysql 登录时密码加单引号或手动输入密码此时 $2 没有被解析成空,与数据库中的密码不一致无法登录,而密码加双引号或不加时 $2 被解析成空,刚好和数据库的密码一致此时能正常登录数据库。下面我们新建一个用户密码设置成:abcUY ,验证一下。
mysql> create user test1@'%' identified by 'abcUY'; Query OK, 0 rows affected (0.03 sec) mysql> select user,host,authentication_string from mysql.user where user in ('app','test','test1'); +-------+------+-------------------------------------------+ | user | host | authentication_string | +-------+------+-------------------------------------------+ | app | % | *06E0B7BA0149152EE2A387A144A2DF9ACC492297 | | test | % | *7258A15F121DD9F6F7C40C08D34A3DB5ED8C8CB5 | | test1 | % | *06E0B7BA0149152EE2A387A144A2DF9ACC492297 | +-------+------+-------------------------------------------+
比较用户 app 与 test1 的 authentication_string 字段发现一致,说明 app 密码确实是 abcUY 。其实不止$符会有这个问题,其它特殊字符也会存上以上问题。所以在新建用户或登录数据库时如果密码包含特殊字符需要注意是否会被解析的问题。
另外在使用 login-path 免密登录配置时,如果密码包含“#”符号,存在一个 bug(https://bugs.mysql.com/bug.php?id=95597)正常配置的密码无法登录到数据库,需要加上双引号。测试如下:
mysql> create user app2@'%' identified by '123#abc'; Query OK, 0 rows affected (0.01 sec) [root@node3 ~]# mysql_config_editor set --login-path=app --user=app2 --host=127.0.0.1 -p Enter password:输入123#abc [root@node3 ~]# mysql --login-path=app ERROR 1045 (28000): Access denied for user 'app2'@'127.0.0.1' (using password: YES) #规避这个bug也很简单,配置时输入密码加上双引号 [root@node3 ~]# mysql_config_editor set --login-path=app --user=app2 --host=127.0.0.1 -p Enter password: 输入"123#abc" [root@node3 ~]# mysql --login-path=app Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 15542 Server version: 8.0.18 MySQL Community Server - GPL Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
该 bug 在 MySQL 5.7.33 ,MySQL 8.0.23 修复。
总结
1.新建用户及登录用户时如果密码存在特殊字符需要注意特殊字符会被解析成其它字符,需加上单引号或加上转义字符\。
2.在 MySQL 5.7.33 与 MySQL 8.0.23 版本前使用 login-path 时密码存在”#”时,配置时输入密码需要加上双引号。