第4章 MySQL 安全管理

数据库系统安全相关因素

所处网络环境(互联网?局域网?)、主机防护、数据库自带防护、代码防护(SQL注入攻击、代码不规范)

MySQL权限系统介绍

权限系统简介

MySQL 的权限系统在实现上比较简单,相关权限信息主要存储在几个被称为granttables 的系统表中,即: 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 以及DROPUSER 命令来进行用户和权限的变更操作,尽量减少直接修改grant tables 来实现用户和权限变更的操作。

权限授予与去除

要为某个用户授权,可以使用GRANT 命令,要去除某个用户已有的权限则使用REVOKE命令。当然,出了这两者之外还有一种比较暴力的办法,那就是直接更新grant tables 系统表。当给某个用户授权的时候,不仅需要指定用户名,同时还要指定来访主机。如果在授权的时候仅指定用户名,则MySQL 会自动认为是对'username'@'%'授权。要去除某个用户的的权限同样也需要指定来访主机。

可能有些时候我们还会需要查看某个用户目前拥有的权限,这可以通过两个方式实现,首先是通过执行“SHOW GRANTS FOR 'username'@'hostname'” 命令来获取之前该用户身上的所有授权。另一种方法是查询grant tables 里面的权限信息。

(就2个方法:要么通过grant系列命令来修改,要么直接操作系统tables来修改)

权限级别

MySQL 中的权限分为五个级别,分别如下:

Global Level

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

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

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 这三层的权限。

Table Level

Database Level 之下就是Table Level 的权限了,Table Level 的权限可以被Global Level 和Database Level 的权限所覆盖,同时也能覆盖Column Level 和Routine Level 的权限。Table Level 的权限作用范围是授权语句中所指定数据库的指定表。

Column Level

Column Level 的权限作用范围就更小了,仅仅是某个表的指定的某个(活某些)列。由于权限的覆盖原则,Column Level 的权限同样可以被Global,Database,Table 这三个级别的权限中的相同级别所覆盖,而且由于Column Level 所针对的权限和Routine Level的权限作用域没有重合部分,所以不会有覆盖与被覆盖的关系。针对Column Level 级别的权限仅有INSERT,SELECT 和UPDATE 这三种。Column Level 的权限授权语句语法基本和TableLevel 差不多,只是需要在权限名称后面将需要授权的列名列表通过括号括起来,

Routine Level

Routine Level 的权限主要只有EXECUTE 和ALTER ROUTINE 两种,主要针对的对象是procedure 和function 这两种对象,在授予Routine Level 权限的时候,需要指定数据库和相关对象

GRANT

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

注意

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

MySQL访问控制实现原理

MySQL 访问控制实际上由两个功能模块共同组成,一个是用户管理模块,另一个就是访问控制模块。用户管理模块决定造访客人能否进门,而访问控制模块则决定每个客人进门能拿什么不能拿什么。

那内存结构中的权限信息更新之后对已经连接上的用户何时生效呢?

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

第一步 用户管理

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

第二步 访问控制

当客户端连接通过用户管理模块的验证,可连接上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。

mysql.host在MySQL 访问控制模块中所实现的功能比较特殊,和其他几个grant tables不太一样。首先是mysql.host 中的权限数据不是(也不能)通过GRANT 或者REVOKE 来授予或者去除,必须通过手工通过INSERT、UPDATE 和DELETE 命令来修改其中的数据。其次是其中的权限数据无法单独生效,必须通过和mysql.db 权限表的数据一起才能生效。而且仅当mysql.db 中存在不完整(某些场景下的特殊设置)的时候,才会促使访问控制模块再结合mysql.host 中查找是否有相应的补充权限数据实现以达到权限校验的目的。

猜你喜欢

转载自blog.csdn.net/attack_breast/article/details/82559167
今日推荐