首页 > 代码库 > 第四章:4.2MySQL 权限系统介绍

第四章:4.2MySQL 权限系统介绍

4.2.1 权限系统简介
  MySQL 的权限系统在实现上比较简单,相关权限信息主要存储在几个被称为grant
tables 的系统表中,即: mysql.User,mysql.db,mysql.Host,mysql.table_priv 和
mysql.column_priv。由于权限信息数据量比较小,而且访问又非常频繁,所以Mysql 在启
动的时候,就会将所有的权限信息都Load 到内存中保存在几个特定的结构中。所以才有我
们每次手工修改了权限相关的表之后,都需要执行“FLUSH PRIVILEGES”命令重新加载MySQL
的权限信息。当然,如果我们通过GRANT,REVOKE 或者DROP USER 命令来修改相关权限,则
不需要手工执行FLUSH PRIVILEGES 命令,因为通过GRANT,REVOKE 或者DROP USER 命令所
做的权限修改在修改系统表的同时也会更新内存结构中的权限信息。在MySQL5.0.2 或更高
版本的时候,MySQL 还增加了CREATE USER 命令,以此创建无任何特别权限(仅拥有初始USAGE
权限)的用户,通过CREATE USER 命令创建新了新用户之后,新用户的信息也会自动更新到
内存结构中。所以,建议读者一般情况下尽量使用GRANT,REVOKE,CREATE USER 以及DROP
USER 命令来进行用户和权限的变更操作,尽量减少直接修改grant tables 来实现用户和权
限变更的操作。

4.2.2 权限授予与去除
  要为某个用户授权,可以使用GRANT 命令,要去除某个用户已有的权限则使用REVOKE
命令。当然,出了这两者之外还有一种比较暴力的办法,那就是直接更新grant tables 系
统表。当给某个用户授权的时候,不仅需要指定用户名,同时还要指定来访主机。如果在授
权的时候仅指定用户名,则MySQL 会自动认为是对‘username‘@‘%‘授权。要去除某个用户的
的权限同样也需要指定来访主机。
  可能有些时候我们还会需要查看某个用户目前拥有的权限,这可以通过两个方式实现,
首先是通过执行“SHOW GRANTS FOR ‘username‘@‘hostname‘” 命令来获取之前该用户身上
的所有授权。另一种方法是查询grant tables 里面的权限信息。

4.2.3 权限级别
MySQL 中的权限分为五个级别,分别如下:
1、Global Level:
  Global Level 的权限控制又称为全局权限控制,所有权限信息都保存在mysql.user 表
中。Global Level 的所有权限都是针对整个mysqld 的,对所有的数据库下的所有表及所有
字段都有效。如果一个权限是以Global Level 来授予的,则会覆盖其他所有级别的相同权
限设置。比如我们首先给abc 用户授权可以UPDATE 指定数据库如test 的t 表,然后又在
全局级别REVOKE 掉了abc 用户对所有数据库的所有表的UPDATE 权限。则这时候的abc 用户
将不再拥有用对test.t 表的更新权限。Global Level 主要有如下这些权限(见表4-1):

  要授予Global Level 的权限,则只需要在执行GRANT 命令的时候,用“*.*”来指定适
用范围是Global 的即可,当有多个权限需要授予的时候,也并不需要多次重复执行GRANT
命令,只需要一次将所有需要的权限名称通过逗号(“,”)分隔开即可,如下:
  

  root@localhost : mysql 05:14:35> GRANT SELECT,UPDATE,DELETE,INSERT ON *.*
TO ‘def‘@‘localhost‘;
Query OK, 0 rows affected (0.00 sec)

 

2、Database Level

  Database Level 是在Global Level 之下,其他三个Level 之上的权限级别,其作用域
即为所指定整个数据库中的所有对象。与Global Level 的权限相比,Database Level 主要
少了以下几个权限:CREATE USER,FILE,PROCESS,RELOAD,REPLICATION CLIENT,REPLICATION
SLAVE,SHOW DATABASES,SHUTDOWN,SUPER 和USAGE 这几个权限,没有增加任何权限。之
前我们说过Global Level 的权限会覆盖底下其他四层的相同权限,Database Level 也一样,
虽然他自己可能会被Global Level 的权限设置所覆盖,但同时他也能覆盖比他更下层的
Table,Column 和Routine 这三层的权限。

如果要授予Database Level 的权限,则可以有两种实现方式:
1、在执行GRANT 命令的时候,通过“database.*”来限定权限作用域为database 整个
数据库,如下:
  

  root@localhost : mysql 06:06:26> GRANT ALTER ON test.* TO ‘def‘@‘localhost‘;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 06:12:45> SHOW GRANTS FOR def@localhost;
+------------------------------------------------------------------+
| Grants for def@localhost |
+------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO ‘def‘@‘localhost‘ |
| GRANT ALTER ON `test`.* TO ‘def‘@‘localhost‘ |
+------------------------------------------------------------------+

2、先通过USE 命令选定需要授权的数据库,然后通过“*”来限定作用域,这样授权的
作用域实际上就是当前选定的整个数据库。
  root@localhost : mysql 06:14:05> USE test;
Database changed
root@localhost : test 06:13:10> GRANT DROP ON * TO ‘def‘@‘localhost‘;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 06:15:26> SHOW GRANTS FOR def@localhost;
+------------------------------------------------------------------+
| Grants for def@localhost |
+------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO ‘def‘@‘localhost‘ |
| GRANT DROP, ALTER ON `test`.* TO ‘def‘@‘localhost‘ |
+------------------------------------------------------------------+

  在授予权限的时候,如果有相同的权限需要授予多个用户,我们也可以在授权语句中一
次写上多个用户信息,通过逗号(,)分隔开就可以了,如下:
root@localhost : mysql 05:22:32> grant create on perf.* to
‘abc‘@‘localhost‘,‘def‘@‘localhost‘;
Query OK, 0 rows affected (0.00 sec)
root@localhost : mysql 05:22:46> SHOW GRANTS FOR def@localhost;
+------------------------------------------------------------------+
| Grants for def@localhost |
+------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO ‘def‘@‘localhost‘ |
| GRANT DROP, ALTER ON `test`.* TO ‘def‘@‘localhost‘ |
| GRANT CREATE ON `perf`.* TO ‘def‘@‘localhost‘ |
+------------------------------------------------------------------
+

3 rows in set (0.00 sec)
root@localhost : mysql 05:23:13> SHOW GRANTS FOR abc@localhost;
+------------------------------------------------------------------+
| Grants for abc@localhost |
+------------------------------------------------------------------+
| GRANT CREATE ON `perf`.* TO ‘abc‘@‘localhost‘ |
| GRANT SELECT ON `test`.* TO ‘abc‘@‘localhost‘ |
+------------------------------------------------------------------+
3 rows in set (0.00 sec)

3、Table Level
  Database Level 之下就是Table Level 的权限了,Table Level 的权限可以被Global
Level 和Database Level 的权限所覆盖,同时也能覆盖Column Level 和Routine Level 的
权限。

  Table Level 的权限作用范围是授权语句中所指定数据库的指定表。如可以通过如下语
句给test 数据库的t1 表授权:
root@localhost : test 12:02:15> GRANT INDEX ON test.t1 TO
‘abc‘@‘%.jianzhaoyang.com‘;
Query OK, 0 rows affected, 1 warning (0.00 sec)
root@localhost : test 12:02:53> SHOW GRANTS FOR ‘abc‘@‘%.jianzhaoyang.com‘;
+----------------------------------------------------------+
| Grants for abc@*.jianzhaoyang.com |
+----------------------------------------------------------+
| GRANT USAGE ON *.* TO ‘abc‘@‘%.jianzhaoyang.com‘ |
| GRANT INDEX ON `test`.`t1` TO ‘abc‘@‘%.jianzhaoyang.com‘ |
+----------------------------------------------------------+

  上面的授权语句在测试给test 数据库的t1 表授予Table Level 的权限的同时,还测试
了将权限授予含有通配符“%”的所有“.jianzhaoyang.com”主机。其中的USAGE 权限是每
个用户都有的最基本权限。
  Table Level 的权限由于其作用域仅限于某个特定的表,所以权限种类也比较少,仅有
ALTER,CREATE,DELETE,DROP,INDEX,INSERT,SELECT UPDATE 这八种权限。

4、Column Level
  Column Level 的权限作用范围就更小了,仅仅是某个表的指定的某个(活某些)列。
由于权限的覆盖原则,Column Level 的权限同样可以被Global,Database,Table 这三个
级别的权限中的相同级别所覆盖,而且由于Column Level 所针对的权限和Routine Level
的权限作用域没有重合部分,所以不会有覆盖与被覆盖的关系。针对Column Level 级别的
权限仅有INSERT,SELECT 和UPDATE 这三种。Column Level 的权限授权语句语法基本和Table
Level 差不多,只是需要在权限名称后面将需要授权的列名列表通过括号括起来,如下:
   root@localhost : test 12:14:46> GRANT SELECT(id,value) ON test.t2 TO
‘abc‘@‘%.jianzhaoyang.com‘;
Query OK, 0 rows affected(0.00 sec)
root@localhost : test 12:16:49> SHOW GRANTS FOR ‘abc‘@‘%.jianzhaoyang.com‘;
+-----------------------------------------------------------------------+
| Grants for abc@*.jianzhaoyang.com |
+-----------------------------------------------------------------------+
| GRANT USAGE ON *.* TO ‘abc‘@‘%.jianzhaoyang.com‘ |
| GRANT SELECT (value, id) ON `test`.`t2` TO ‘abc‘@‘%.jianzhaoyang.com‘ |
| GRANT INDEX ON `test`.`t1` TO ‘abc‘@‘%.jianzhaoyang.com‘ |
+-----------------------------------------------------------------------+

注意:当某个用户在向某个表插入(INSERT)数据的时候,如果该用户在该表中某列上
面没有INSERT 权限,则该列的数据将以默认值填充。这一点和很多其他的数据库都有一些
区别,是MySQL 自己在SQL 上面所做的扩展。

5、Routine Level
  Routine Level 的权限主要只有EXECUTE 和ALTER ROUTINE 两种,主要针对的对象是
procedure 和function 这两种对象,在授予Routine Level 权限的时候,需要指定数据库
和相关对象,如:
  root@localhost : test 04:03:26> GRANT EXECUTE ON test.p1 to
  ‘abc‘@‘localhost‘;
  Query OK, 0 rows affected (0.00 sec)
除了上面几类权限之外,还有一个非常特殊的权限GRANT,拥有GRANT 权限的用户可以

  除了上面几类权限之外,还有一个非常特殊的权限GRANT,拥有GRANT 权限的用户可以
将自身所拥有的任何权限全部授予其他任何用户,所以GRANT 权限是一个非常特殊也非常重
要的权限。GRANT 权限的授予方式也和其他任何权限都不太一样,通常都是通过在执行GRANT
授权语句的时候在最后添加WITH GRANT OPTION 子句达到授予GRANT 权限的目的。

  此外,我们还可以通过GRANT ALL 语句授予某个Level 的所有可用权限给某个用户,
如:
root@localhost : test 04:15:48> grant all on test.t5 to ‘abc‘;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 04:27:39> grant all on perf.* to ‘abc‘;
Query OK, 0 rows affected (0.00 sec)
root@localhost : test 04:27:52> show grants for ‘abc‘;
+--------------------------------------------------+
| Grants for abc@% |
+--------------------------------------------------+
| GRANT USAGE ON *.* TO ‘abc‘@‘%‘ |
| GRANT ALL PRIVILEGES ON `perf`.* TO ‘abc‘@‘%‘ |
| GRANT ALL PRIVILEGES ON `test`.`t5` TO ‘abc‘@‘%‘ |
+--------------------------------------------------+

  在以上五个Level 的权限中,Table、Column 和Routine 三者在授权中所依赖(或者引
用)的对象必须是已经存在的,而不像Database Level 的权限授予,可以在当前不存在该
数据库的时候就完成授权。

4.2.4 MySQL访问控制实现原理

  MySQL 访问控制实际上由两个功能模块共同组成,从第一篇的第二章架构组成中可以看
到,一个是负责“看守MySQL 大门”的用户管理模块,另一个就是负责监控来访者每一个动
作的访问控制模块。用户管理模块决定造访客人能否进门,而访问控制模块则决定每个客人
进门能拿什么不能拿什么。下面是一张MySQL 中实现访问控制的简单流程图(见图4-2):

1、用户管理
  我们先看看用户管理模块是如何工作的。在MySQL 中,用户访问控制部分的实现比较简
单,所有授权用户都存放在一个系统表中:mysql.user,当然这个表不仅仅存放了授权用户
的基本信息,还存放有部分细化的权限信息。用户管理模块需要使用的信息很少,主要就是
Host,User,Password 这三项,都在mysql.user 表中,如下:

sky@localhost : (none) 12:35:04> USE mysql;
Database changed
sky@localhost : mysql 12:35:08> DESC user;
+---------------+--------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------------+------+-----+---------+-------+
| Host | char(60) | NO | PRI | | |
| User | char(16) | NO | PRI | | |
| Password | char(41) | NO | | | |
... ...
+---------------+--------------------+------+-----+---------+-------+

  一个用户要想访问MySQL,至少需要提供上面列出的这三项数据,MySQL 才能判断是否
该让他“进门”。这三项实际上由量部分组成:访问者来源的主机名(或者主机IP 地址信息)
和访问者的来访“暗号”(登录用户名和登录密码),这两部分中的任何一个没有能够匹配上
都无法让看守大门的用户管理模块乖乖开门。其中Host 信息存放的是MySQL 允许所对应的
User 的信任主机,可以是某个具体的主机名(如:mytest)或域名(如:www.domain.com),
也可以是以“%”来充当通配符的某个域名集合(如:%.domain.com);也可以是一个具体的
IP 地址(如:1.2.3.4),同样也可以是存在通配符的域名集合(如:1.2.3.%);还可以用“%”
来代表任何主机,就是不对访问者的主机做任何限制。如以下设置:
root@localhost : mysql 01:18:12> SELECT host,user,password FROM user ORDER BY
user;

  但是这里有一个比较特殊的访问限制,如果要通过localhost 访问的话,必须要有一条
专门针对localhost 的授权信息,即使不对任何主机做限制也不行。如下例所示,存在def@%
的用户设置,但是如果不使用-h 参数来访问,则登录会被拒绝,因为mysql 在默认情况下
会连接localhost:

sky@sky:~$ mysql -u def -p
Enter password:
ERROR 1045 (28000): Access denied for user ‘def‘@‘localhost‘ (using
password: YES)

  但是当通过-h 参数,明确指定了访问的主机地址之后就没问题了,如下:
sky@sky:~$ mysql -u def -p -h 127.0.0.1
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 17
Server version: 5.0.51a-log Source distribution
Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the buffer.
def@127.0.0.1 : (none) 01:26:04>

 

  如果我们有一条localhost 的访问授权则可以不使用-h 参数来指定登录host 而连接默
认的localhost:
sky@sky:~$ mysql -u abc -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 18
Server version: 5.0.51a-log Source distribution
Type ‘help;‘ or ‘\h‘ for help. Type ‘\c‘ to clear the buffer.
abc@localhost : (none) 01:27:19> exit
Bye

  如果MySQL 正在运行之中的时候,我们对系统做了权限调整,那调整之后的权限什么时
候会生效呢?
  我们先了解何时MySQL 存放于内存结构中的权限信息被更新:FLUSH PRIVILEGES 会强
行让MySQL 更新Load 到内存中的权限信息;GRANT、REVOKE 或者CREATE USER 和DROP USER
操作会直接更新内存中俄权限信息;重启MySQL 会让MySQL 完全从grant tables 中读取权
限信息。

  那内存结构中的权限信息更新之后对已经连接上的用户何时生效呢?
  对于Global Level 的权限信息的修改,仅仅只有更改之后新建连接才会用到,对于已
经连接上的session 并不会受到影响。而对于Database Level 的权限信息的修改,只有当
客户端请求执行了“USE database_name”命令之后,才会在重新校验中使用到新的权限信
息。所以有些时候如果在做了比较紧急的Global 和Database 这两个Level 的权限变更之后,
可能需要通过“KILL”命令将已经连接在MySQL 中的session 杀掉强迫他们重新连接以使
用更新后的权限。对于Table Level 和Column Level 的权限,则会在下一次需要使用到该
权限的Query 被请求的时候生效,也就是说,对于应用来讲,这两个Level 的权限,更新之
后立刻就生效了,而不会需要执行“KILL”命令。

2、访问控制
  当客户端连接通过用户管理模块的验证,可连接上MySQL Server 之后,就会发送各种
Query 和Command 给MySQL Server,以实现客户端应用的各种功能。当MySQL 接收到客户
端的请求之后,访问控制模块是需要校验该用户是否满足提交的请求所需要的权限。权限校
验过程是从最大范围的权限往最小范围的权限开始依次校验所涉及到的每个对象的每个权
限。

  在验证所有所需权限的时候,MySQL 首先会查找存储在内存结构中的权限数据,首先查
找Global Level 权限,如果所需权限在Global Level 都有定义(GRANT 或者REVOKE),
则完成权限校验(通过或者拒绝),如果没有找到所有权限的定义,则会继续往后查找
Database Level 权限,进行Global Level 未定义的所需权限的校验,如果仍然没有能够
找到所有所需权限的定义,MySQL 会继续往更小范围的权限定义域查找,也就是Table
Level,最后则是Column Level 或者Routine Level。

  下面我们就以客户端通过abc@localhost 连接后请求如下Query 我为例:
SELECT id,name FROM test.t4 where status = ‘deleted‘;

 

  在前面我们了解到MySQL 的grant tables 有mysql.user,mysql.db,mysql.host,
mysql.table_priv 和mysql.column_priv 这五个,我想出了mysql.host 之外的四个都是非
常容易理解的,每一个表针对MySQL 中的一种逻辑对象,存放某一特定Level 的权限,唯独
mysql.host 稍有区别。我们现在就来看看mysql.host 权限表到底在MySQL 的访问控制中充
当了一个什么样的角色呢?

  mysql.host在MySQL 访问控制模块中所实现的功能比较特殊,和其他几个grant tables
不太一样。首先是mysql.host 中的权限数据不是(也不能)通过GRANT 或者REVOKE 来授予
或者去除,必须通过手工通过INSERT、UPDATE 和DELETE 命令来修改其中的数据。其次是
其中的权限数据无法单独生效,必须通过和mysql.db 权限表的数据一起才能生效。而且仅
当mysql.db 中存在不完整(某些场景下的特殊设置)的时候,才会促使访问控制模块再结
合mysql.host 中查找是否有相应的补充权限数据实现以达到权限校验的目的,就比如上图
中所示。在mysql.db 中无法找到满足权限校验的所有条件的数据(db.User = ‘abc‘ AND
db.host = ‘localhost‘ AND db.Database_name = ‘test‘),则说明在mysql.db 中无法完
成权限校验,所以也不会直接就校验db.Select_priv 的值是否为‘Y‘。但是mysql.db 中有
db.User = ‘abc‘ AND db.Database_name = ‘test‘ AND db.host = ‘‘ 这样一条权限信息
存在,大家可能注意到了这条权限信息中的db.host 中是空值,注意是空值而不是‘%‘这个
通配符哦。当MySQL 注意到有这样一条权限信息存在的时候,就该是mysql.host 中所存放
的权限信息出场的时候了。这时候,MySQL 会检测mysql.host 中是否存在满足如下条件的
权限信息:host.Host = ‘localhost‘ AND host.Db = ‘test‘。如果存在,则开始进行
Select_priv 权限的校验。由于权限信息存在于mysql.db 和mysql.host 两者之中,而且是
两者信息合并才能满足要求,所以Select_priv 的校验也需要两表都为‘Y‘才能满足要求,
通过校验。

  我们已经清楚,MySQL 的权限是授予“username@hostname”的,也就是说,至少需要
用户名和主机名二者才能确定一个访问者的权限。又由于hostname 可以是一个含有通配符
的域名,也可以是一个含有通配符的IP 地址段。那么如果同一个用户有两条权限信息,一
条是针对特定域名的,另外一个是含有通配符的域名,而且前者属于后者包含。这时候MySQL
如何来确定权限信息呢?实际上MySQL 永远优先考虑更精确范围的权限。在MySQL 内部会按
照username 和hostname 作一个排序,对于相同username 的权限,其host 信息越接近访问
者的来源host,则排序位置越靠前,则越早被校验使用到。而且,MySQL 在权限校验过程中,
只要找到匹配的权限之后,就不会再继续往后查找是否还有匹配的权限信息,而直接完成校
验过程。

  大家应该也看到了在mysql.user 这个权限表中有max_questions,max_updates,
max_connections,max_user_connections 这四列,前面三列是从MySQL4.0.2 版本才开始
有的,其功能是对访问用户进行每小时所使用资源的限制,而最后的max_user_connections
则是从MySQL5.0.3 版本才开始有的,他和max_connections 的区别是限制耽搁用户的连接
总次数,而不是每小时的连接次数。而要使这四项限制生效,需要在创建用户或者给用户授
权的时候加上以下四种子句:
max_questions : WITH MAX_QUERIES_PER_HOUR n;
max_updates : WITH MAX_UPDATES_PER_HOUR n;
max_connections : WITH MAX_CONNECTIONS_PER_HOUR n;
max_user_connections: MAX_USER_CONNECTIONS。
四个子句可以同时使用,如:

“ WITH MAX_QUERIES_PER_HOUR 5000 MAX_CONNECTIONS_PER_HOUR 10
MAX_USER_CONNECTIONS 10000”。

 

4.3MySQL 访问授权策略

  首先,需要了解来访主机。

通过使用具体的主机名和IP 地址来限定来访主机。

  其次,了解用户需求。

了解用户相对该系统扮演什么角色,比如是只读的,还是读写兼用的等等。

  再次,要为工作分类。

  比如将执行备份工作、复制工作、常规应用访问、只读应用访问和日常管理
工作分别分理出单独的特定帐户来授予各自所需权限。这样,既可以让安全风险尽量降低,
也可以让同类同级别的相似权限合并在一起,不互相交织在一起。对于PROCESS,FILE 和
SUPER 这样的特殊权限,仅仅只有管理类帐号才需要,不应该授予其他非管理帐号。

  最后,确保只有绝对必要者拥有GRANT OPTION 权限。
之前在权限系统介绍的时候我们已经了解到GRANT OPTION 权限的特殊性,和拥有该权
限之后的潜在风险,所以在这里也就不再累述了。总之,为了安全考虑,拥有GRANT OPTION
权限的用户越少越好,尽可能只让拥有超级权限的用户才拥有GRANT OPTION 权限。

4.4 安全设置注意事项

仅仅提供本地访问,禁止网络服务,

启动MySQL的时候通过使用“--skip-networking”参数选项,让MySQL 不通过TCP/IP 监听网络请求,
而仅仅通过命名管道或共享内存(在Windows 中)或Unix 套接字文件(在Unix 中)来和客户端
连接交互。

其次,在第二层防线主机上面也有以下一些需要注意的地方。

OS 安全方面。关闭MySQL Server 主机上面任何不需要的服务,这不仅能从安全方面减
少潜在隐患,还能减轻主机的部分负担,尽可能提高性能。

  用非root 用户运行MySQL。这在MySQL 官方文档中也有非常明显的提示,提醒用户不
要使用root 用户来运行MySQL。因为如果使用root 用户运行MySQL,那么mysqld 的进程就
会拥有root 用户所拥有的权限,任何具有FILE 权限的MySQL 用户就可以在MySQL 中向系统
中的任何位置写入文件。

  文件和进程安全。合理设置文件的权限属性,MySQL 相关的数据和日志文件和所在的文
件夹属主和所属组都设置为mysql,且禁用其他所有用户(除了拥有超级权限的用户,如
root)的读写权限。以防止数据或者日志文件被窃取或破坏。因为如果一个用户对MySQL
的数据文件有读取权限的话,可以很容易将数据复制。binlog 文件也很容易还原整个数据
库。而如果有写权限的话就更糟了,因为有了写权限,数据或者日志文件就有被破坏或者删
除的风险存在。保护好socket 文件的安全,尽量不要使用默认的位置(如/tmp/mysql.sock),
以防止被有意或无意的删除。

  再次,就是最后第三道防线MySQL 自身方面的安全设置注意事项。

用户设置。我们必须确保任何可以访问数据库的用户都有一个比较复杂的内容作为密
码,而不是非常简单或者比较有规律的字符,以防止被使用字典破解程序攻破。在MySQL
初始安装完成之后,系统中可能存在一个不需要任何密码的root 用户,有些版本安装完成
之后还会存在一个可以通过localhost 登录的没有用户名和密码的帐号。这些帐号会给系统
带来极大的安全隐患,所以我们必须在正式启用之前尽早删除,或者设置一个比较安全的密
码。对于密码数据的存放,也不要存放在简单的文本文件之中,而应该使用专业密码管理软
件来管理(如KeePass)。同时,就像之前在网络安全注意事项部分讲到的那样,尽可能为
每一个帐户限定一定范围的可访问主机。尤其是拥有超级权限的MySQL root 帐号,尽量确
保只能通过localhost 访问。

安全参数

  在MySQL 官方参考手册中也有说明,不论是从安全方面考虑还是从性能以及
功能稳定性方面考虑,不需要使用的功能模块尽量都不要启用。例如,如果不需要使用用户
自定义函数,就不要在启动的时候使用“--allow-suspicious-udfs”参数选项,以防止被
别有居心的潜在威胁者利用此功能而对MySQL 的安全造成威胁;不需要从本地文件中Load
数据到数据库中,就使用“--local-infile=0”禁用掉可以从客户端机器上Load 文件到数
据库中;使用新的密码规则和校验规则(不要使用“--old-passwords”启动数据库),这项
功能是为了兼容旧版本的密码校验方式的,如无额数必要,不要使用该功能,旧版本的密码
加密方式要比新的方式在安全方面弱很多。

  除了以上这三道防线,我们还应该让连接MySQL 数据库的应用程序足够安全,以防止入
侵者通过应用程序中的漏洞而入侵到应用服务器,最终通过应用程序中的数据库相关关配置
而获取数据库的登录口令。