当密码存储在选项文件中时,MySQL 拒绝登录尝试

当密码存储在选项文件中时,MySQL 拒绝登录尝试

第一的:

  • 我们正在运行 MySQL 5.7.13。
  • 操作系统是 Red Hat Enterprise Linux 7.2。
  • 该问题最早是在使用 Python/Connector 2.1.3 时发现的
  • 系统尚未加入域(尚未)。
  • 所有 MySQL 软件包均从 MySQL 自己的 yum 存储库安装!

场景:我正在尝试构建一个简单的监控解决方案,以密切关注我控制下的大约一百台机器的某些方面(并且在不久的将来数量可能会增加);我需要能够向安全部门生成报告,例如,向他们提供软件包版本以证明最近披露的漏洞已在 y 台机器中的 x 台上得到修补。

我可以使用 Ansible 等实时提取这些信息,但 a) 无法保证所有机器在任何给定时间都处于连接状态,并且 b) 管理工具可以提供当前状态,但不一定是我可能需要报告的历史数据。因此,从我的角度来看,解决方案是一个可以容纳每个系统记录的数据库;当系统更新时,我们会将新记录放入数据库中以指示更改,然后我可以稍后将其提取出来。

为此,我们使用 MySQL 数据库。目前,我们有一个简单的 MySQL 安装,其中创建了一个小表集并定义了一个非 root 用户。MySQL 中定义的用户列表为:

select user, host, authentication_string from mysql.user;
+-------------+-----------+-------------------------------------------+
| user        | host      | authentication_string                     |
+-------------+-----------+-------------------------------------------+
| root        | localhost | *D971D136A477A4C205AEF706...              |
| mysql.sys   | localhost | *THISISNOTAVALIDPASSWORDT...              |
| pkg_manager | localhost | *E91158E2E26F343D6639E4BD...              |
+-------------+-----------+-------------------------------------------+

因此不存在空字符串用户名。

有问题的账户是 pkg_manager 账户。授予它的权限是:

mysql> show grants for 'pkg_manager'@'localhost';
+-------------------------------------------------------------------------------------+
| Grants for pkg_manager@localhost                                                    |
+-------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO 'pkg_manager'@'localhost'                                     |
| GRANT SELECT, INSERT ON `panopticon`.`package` TO 'pkg_manager'@'localhost'         |
| GRANT SELECT, INSERT ON `panopticon`.`package_history` TO 'pkg_manager'@'localhost' |
+-------------------------------------------------------------------------------------+

pkg_manager 帐户连接没有问题,使用如下命令行:

[~]$ mysql -u pkg_manager -p --database=panopticon
Enter password: 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.13 MySQL Community Server (GPL)

Copyright (c) 2000, 2016, 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> 

但是,我需要允许自动化工具登录数据库(它将提取当前未更新的系统列表,检查其中哪些系统当前在线,然后向它们推送更新并记录每个成功的更新。)该工具将用 Python 编写,我已经下载了 Python 2.1.3 连接器。

我们为该工具构建了一个 options.cnf 文件,并将其存储在受限目录中(最初为 root:root 0700,当前为:)。使用以下连接器在 python 中打开连接的初始测试:

connection = mysql.connector.connect(option_files='/path/to/options.cnf')

导致错误 1045,SQLState 28000 消息。(实际上,首先还有其他一些事情,主要涉及指定套接字路径。然而,这些都已清除,我们知道它们已经解决了,因为现在 MySQL 日志正在报告失败的连接尝试。)

我们知道这部分是有效的,因为 1045 错误的完整详细信息是“拒绝用户‘pkg_manager’@‘localhost’访问(使用密码:YES)”。因此,它正在读取选项文件,识别 pkg_manager 帐户,并在文件中查看密码条目(如果没有密码条目,则消息的结尾将变为“(使用密码:NO)”。

然后,我们尝试使用相同的选项文件来简化问题,并在其中创建一个客户端部分,指定在connector_python部分中存在的所有相同字段。这也失败了:

mysql --defaults-file="/path/to/options.cnf"

但是,我们知道在命令行上手动指定登录信息时该帐户可以正常工作,如上所示。

经过数小时搜索用户登录失败的经历后,我们决定尝试一种混合方法 - 使用--defaults文件的命令行登录,同时也指定-p强制我们在命令行上输入密码:

[~]$ mysql --defaults-file="/etc/pkg_manager/db_info/options.cnf" -p
Enter password: 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
...
mysql>

因此,我们知道选项配置文件中提供的其余信息是正确的。只需运行 mysql --print-defaults(以确定路径搜索列表中是否有任何其他可能干扰的选项文件)即可列出零个启动选项,因此没有其他选项会妨碍。

至此,我几乎陷入了困境。官方 MySQL 文档明确指出,除了加密的本地登录文件外,您还可以将未加密的密码存储在选项文件中: http://dev.mysql.com/doc/refman/5.7/en/password-security-user.html

但显然,它不起作用。我查看了可以设置的配置文件变量列表,没有看到任何似乎会阻止选项文件中的密码验证的变量。我已将错误日志记录设置为 3,但除了一行注释表明来自“pkg_manager”@“localhost”的连接尝试被拒绝外,没有提供有关连接问题的详细信息。

在我忘记之前,这里是选项文件(无密码):

1 # Options file for pkg_manager, easy way to "securely" store database login info.
2 [connector_python]
3 user="pkg_manager"
4 password="*********"
5 database="panopticon"
6 host="localhost"
7 unix_socket="/var/lib/mysql/mysql.sock"
8 
9 [client]
10 user="pkg_manager"
11 password="*********"
12 database="panopticon"
13 host="localhost"
14 socket="/var/lib/mysql/mysql.sock"

这是 /etc/my.cnf 文件:

1 # For advice on how to change settings please see
2 # http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
3 
4 [mysqld]
5 #
6 # Remove leading # and set to the amount of RAM for the most important data
7 # cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
8 # innodb_buffer_pool_size = 128M
9 #
10 # Remove leading # to turn on a very important data integrity option: logging
11 # changes to the binary log between backups.
12 # log_bin
13 #
14 # Remove leading # to set options mainly useful for reporting servers.
15 # The server defaults are faster for transactions and fast SELECTs.
16 # Adjust sizes as needed, experiment to find the optimal values.
17 # join_buffer_size = 128M
18 # sort_buffer_size = 2M
19 # read_rnd_buffer_size = 2M
20 datadir=/data/panopticon
21 socket=/var/lib/mysql/mysql.sock
22 
23 skip-networking
24 
25 # Disabling symbolic-links is recommended to prevent assorted security risks
26 symbolic-links=0
27 
28 log-error=/var/log/mysqld.log
29 log_error_verbosity=3
30 general-log=1
31 general_log_file=/var/log/mysql_general.log
32 pid-file=/var/run/mysqld/mysqld.pid

答案1

我终于有机会花几个小时研究这个问题,并找到了解决方案。正如我所想的那样,它非常简单,但它也违背了多个用户论坛甚至 MySQL 参考文档上发布的建议。

如果我的密码存储在选项文件中的引号中,则无法连接。当我从密码中删除引号时,它就可以连接。我最终检查了 Python 连接器代码才意识到这一点,主要是因为我之前曾尝试删除密码上的引号,但针对的是略有不同的问题,然后我脑子里就把这两个问题混为一谈了。

我注意到,在浏览 Python 连接器代码时,我可以直接实例化选项文件解析器,因此我尝试了一下(将路径作为参数传递到我的选项文件。)当我这样做时,我看到所有选项(包括密码)都已导入解析器状态,并且文件中包含所有引号。但是,在此之后的任何阶段都没有采取措施从密码中删除引号(至少我看到没有),因此当连接器使用解析器打开选项文件时,引号似乎会被包括在内并作为密码的一部分传递给服务器进行身份验证。

我很可能会将此作为错误报告提交给 MySQL 开发人员,因为所有其他选项都可以使用引号正常工作。

相关内容