MySQL:为什么 mysql.db 中有“测试”条目?

Rol*_*DBA 37 mysql security

最近,我发布了一个关于 mysql.db 的问题的答案

然后,我开始想我应该问每个人这个问题:

多年来,我一直注意到在安装 MySQL 5.0+ 时,mysql.db填充了两个条目,允许匿名用户访问测试数据库。

您可以通过运行此查询来查看它:

mysql> select * from mysql.db where SUBSTR(db,1,4) = 'test'\G
*************************** 1. row ***************************
                 Host: %
                   Db: test
                 User:
          Select_priv: Y
          Insert_priv: Y
          Update_priv: Y
          Delete_priv: Y
          Create_priv: Y
            Drop_priv: Y
           Grant_priv: N
      References_priv: Y
           Index_priv: Y
           Alter_priv: Y
Create_tmp_table_priv: Y
     Lock_tables_priv: Y
     Create_view_priv: Y
       Show_view_priv: Y
  Create_routine_priv: Y
   Alter_routine_priv: N
         Execute_priv: N
*************************** 2. row ***************************
                 Host: %
                   Db: test\_%
                 User:
          Select_priv: Y
          Insert_priv: Y
          Update_priv: Y
          Delete_priv: Y
          Create_priv: Y
            Drop_priv: Y
           Grant_priv: N
      References_priv: Y
           Index_priv: Y
           Alter_priv: Y
Create_tmp_table_priv: Y
     Lock_tables_priv: Y
     Create_view_priv: Y
       Show_view_priv: Y
  Create_routine_priv: Y
   Alter_routine_priv: N
         Execute_priv: N
2 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)

这些条目是否mysql.db存在安全风险,如果是,为什么默认情况下将它们添加到新安装中?

更新 2013-06-14 10:13 EDT

今天早上有人低估了我的问题,我真的不明白。鉴于此事件,这就是我花时间进行反驳的原因:

我本周在他们的临时集群中为一个客户安装了 MySQL 5.6.12。我决定检查一下这是否仍然是一个持续存在的问题:

mysql> select version();
+------------+
| version()  |
+------------+
| 5.6.12-log |
+------------+
1 row in set (0.00 sec)

mysql> select db,user,host from mysql.db where LEFT(db,4)='test';
+---------+------+------+
| db      | user | host |
+---------+------+------+
| test    |      | %    |
| test\_% |      | %    |
+---------+------+------+
2 rows in set (0.10 sec)

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2013-06-14 10:10:13 |
+---------------------+
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

你猜怎么着?直到今天这仍然是一个问题!!!

故事的寓意:mysql.db在安装后立即检查并删除匿名登录并立即删除这些测试条目mysql.db

Rol*_*DBA 29

请注意什么MySQL 5.0 认证学习指南

在此处输入图片说明

在第 498 页第 6 段的要点中说:

在 Unix 上,MySQL 带有一个 mysql_secure_installation 脚本,它可以在您的安装上执行几个有用的与安全相关的操作。该脚本具有以下功能:

  • 为 root 帐户设置密码
  • 删除任何可远程访问的 root 帐户。
  • 删除匿名用户帐户。这提高了安全性,因为它可以防止任何人以 root 身份从远程主机连接到 MySQL 服务器的可能性。结果是任何想要以 root 身份连接的人都必须首先能够登录服务器主机,这提供了额外的攻击屏障。
  • 删除测试数据库(如果删除匿名帐户,您可能还想删除他们有权访问的测试数据库)。

要摆脱那些错误的条目,请运行以下命令:

DELETE FROM mysql.db WHERE SUBSTR(db,4) = 'test';
FLUSH PRIVILEGES;
Run Code Online (Sandbox Code Playgroud)

正如@DTest 在他对问题的评论中提到的那样,您也可以为此运行mysql_secure_installation

如果匿名用户可以远程登录 MySQL,则可以发起简单的磁盘攻击来破坏 mysql 安装。下面是一个例子:

USE test
CREATE TABLE rolando_tb (a int);
INSERT INTO rolando_tb VALUES (1);
INSERT INTO rolando_tb SELECT a FROM rolando_tb;
INSERT INTO rolando_tb SELECT a FROM rolando_tb;
INSERT INTO rolando_tb SELECT a FROM rolando_tb;
INSERT INTO rolando_tb SELECT a FROM rolando_tb;
Run Code Online (Sandbox Code Playgroud)

运行 insert 30 次,你会得到一个 7GB 的表

  • 想象一下在测试数据库中创建几个这样的表
  • 想象一下在测试数据库中创建一个存储过程
  • 只要 test 和 test_% 存在于 mysql.db

MySQL AB 还没有完全记录保护 mysql 安装的严重性,我认为 Oracle 今天没有兴趣这样做。

更新 2012-02-18 16:45 EDT

@atxdba 的评论建议只运行“DROP DATABASE test;” 应该是触摸 mysql.db 的首选方法。删除名为的数据库test只是删除打开潜在安全漏洞管道的数据库。

请注意这个查询:

mysql> select user,host,db from mysql.db;
+------+------+---------+
| user | host | db      |
+------+------+---------+
|      | %    | test    |
|      | %    | test\_% |
+------+------+---------+
2 rows in set (0.09 sec)
Run Code Online (Sandbox Code Playgroud)

基于此,匿名用户可以完全访问以下数据库:

  • 测试
  • 测试数据库
  • 测试_001
  • 测试_1
  • 测试数据

虽然匿名用户无法完全访问以下数据库:

  • 测试数据库
  • 测试1
  • 测试数据
  • 测试(Test不同于test在基于Linux的系统,但它仍然是问题的MySQL在Windows上运行)

你必须记住这个基于mysql.db表格的微妙规则。如果你不记得这一点,创建一个名为 test 的数据库test或者一个前 5 个字符为的数据库名test_会重新打开同类型的安全漏洞。

记住这些事情的最安全方法是在初始安装后运行这些行:

DELETE FROM mysql.db WHERE SUBSTR(db,4) = 'test' AND user='';
FLUSH PRIVILEGES;
Run Code Online (Sandbox Code Playgroud)

那么任何具有任何名称的数据库都可以具有适当的身份验证设置。您仍然可以随时运行这两行。

更新 2012-02-24 15:20 EDT

为了公开展示匿名用户在 中的危险mysql.db,我想创建一个只有使用权限的用户。

我将在我的桌面上使用 MySQL 5.5.12

首先看mysql.db

mysql> select user,host,db from mysql.db;
+------+------+---------+
| user | host | db      |
+------+------+---------+
|      | %    | test    |
|      | %    | test\_% |
+------+------+---------+
2 rows in set (0.05 sec)


mysql>
Run Code Online (Sandbox Code Playgroud)

据此,任何匿名 Joe 都可以访问这些数据库。

我将创建一个数据库 test_mysqldb

mysql> create database test_mysqldb;
Query OK, 1 row affected (0.00 sec)

mysql> use test_mysqldb
Database changed
mysql> show tables;
Empty set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

让我们创建一个名为 vanilla@localhost(无密码)的普通用户

mysql> CREATE USER vanilla@localhost;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW GRANTS FOR vanilla@localhost;
+---------------------------------------------+
| Grants for vanilla@localhost                |
+---------------------------------------------+
| GRANT USAGE ON *.* TO 'vanilla'@'localhost' |
+---------------------------------------------+
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

接下来,从 DOS 命令行,让我们连接到 mysql 模式

C:\>mysql -uvanilla -Dmysql
ERROR 1044 (42000): Access denied for user 'vanilla'@'localhost' to database 'mysql'

C:\>
Run Code Online (Sandbox Code Playgroud)

太好了。这正是我所期望的。

接下来,从 DOS 命令行,让我们连接到 test_mysqldb 模式,创建一个表,并用数字加载它

C:\>mysql -uvanilla -Dtest_mysqldb
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.5.12-log MySQL Community Server (GPL)

Copyright (c) 2000, 2010, 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> CREATE TABLE rolando_tb (a bigint unsigned);
Query OK, 0 rows affected (0.06 sec)

mysql> INSERT INTO rolando_tb VALUES (1);
Query OK, 1 row affected (0.06 sec)

mysql> INSERT INTO rolando_tb SELECT * FROM rolando_tb;
Query OK, 1 row affected (0.06 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> INSERT INTO rolando_tb SELECT * FROM rolando_tb;
Query OK, 2 rows affected (0.08 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> INSERT INTO rolando_tb SELECT * FROM rolando_tb;
Query OK, 4 rows affected (0.06 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> INSERT INTO rolando_tb SELECT * FROM rolando_tb;
Query OK, 8 rows affected (0.06 sec)
Records: 8  Duplicates: 0  Warnings: 0

mysql> SELECT * FROM rolando_tb;
+------+
| a    |
+------+
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
|    1 |
+------+
16 rows in set (0.00 sec)

mysql> SELECT database();
+--------------+
| database()   |
+--------------+
| test_mysqldb |
+--------------+
1 row in set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

你看到了吗?具有USAGE特权的用户可以在测试数据库中创建一个表并用数据填充它。这是一个明显而现实的危险。这就是为什么我强烈建议从 mysql.db 中删除这些测试条目以阻止匿名用户访问测试数据库或访问新创建的测试数据库(通过在 default 下创建子文件夹datadir)。

提醒一下,这是你的做法:

DELETE FROM mysql.db WHERE SUBSTR(db,4) = 'test' AND user='';
FLUSH PRIVILEGES;
Run Code Online (Sandbox Code Playgroud)

更新 2013-09-14 20:05 EDT

为了证明它DELETE FROM mysql.db WHERE SUBSTR(db,4) = 'test' AND user='';确实有效,我今天在 MySQL 5.6.13 上运行了它:

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

Copyright (c) 2000, 2013, 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> select db,user,host from mysql.db where LEFT(db,4)='test';
+---------+------+------+
| db      | user | host |
+---------+------+------+
| test    |      | %    |
| test\_% |      | %    |
+---------+------+------+
2 rows in set (0.43 sec)

mysql> delete from mysql.db where LEFT(db,4)='test';
Query OK, 2 rows affected (0.04 sec)

mysql> select db,user,host from mysql.db2 where LEFT(db,4)='test';
Empty set (0.00 sec)

mysql>
Run Code Online (Sandbox Code Playgroud)

就像公益广告一样,请运行

DELETE FROM mysql.db WHERE SUBSTR(db,4) = 'test' AND user='';
FLUSH PRIVILEGES;
Run Code Online (Sandbox Code Playgroud)

或者只是运行mysql-secure-installation并消除这种潜在的危险。