- LAMP网站开发黄金组合Linux+Apache+MySQL+PHP
- 杨明华等编著
- 3020字
- 2020-08-26 19:07:32
6.6 MySQL的外部安全性
上一节介绍了如何保证MySQL数据文件的安全,本节继续讨论另一个方面:通过网络访问数据库的安全性,也称为MySQL的外部安全性。
6.6.1 通过授权表确认访客
MySQL授权表用于控制客户机对服务器的访问权限。MySQL允许多种方法来设置授权表,授权机制非常灵活。如图6-5所示。
图6-5 MySQL授权表确认访客机制
通常,可以通过GRANT和REVOKE语句来实现用户权限控制。另外,在了解了授权表的结构,以及如何使用它们控制权限后,也可以通过直接修改授权表来实现权限控制,还可以进一步在检查表时诊断权限的问题。
授权表在MySQL数据库中,主要包括user、db、host、table_priv和columns_priv五个表,在首次安装MySQL的时候初始化,通过下面命令可以查看到这些表:
mysql> use mysql mysql> show tables; +---------------------- + |Tables_in_mysql | +---------------------- + |columns_priv | |db | |func | |host | |tables_priv | |user | +---------------------- +
其中,func表管理MySQL可以执行的函数库,与权限系统无关。
其余5个表都与MySQL的外部安全性相关。当一个用户提交GRANT语句时,MySQL会在user表中为该用户创建一条用户记录。如果语句指定全局权限(管理权限或适用于所有数据库的权限),也将记录在user表中;如果指定数据库、表和列级权限,则会分别记录在db、tables_priv和columns_priv表中。
6.6.2 检查访问用户合法性
user表记录所有合法用户,以及他们的口令和全局权限信息。注意:在user表启用的权限都是全局权限,可以在所有的数据库上进行操作。例如,如果在user表中为一个用户启用了SELECT权限,那么该用户可以从任何表中查询任何记录。
user表的结构如表6-3所示。
表6-3 user授权表
说明,在user表及下面所介绍的db和host表中,每个数据库(表)的操作权限都作为单独的列,用ENUM(“N”、“Y”)类型声明,所有权限的默认值为“N”(off)。
下面详细介绍user表的几个列,这些列的含义及使用情况可能在下面所介绍的几个表中都通用:
1.Host
该列可以是一个主机名或一个IP地址。特别地,localhost代表本地主机,仅当使用localhost而不是主机名连接时才匹配。例如,假定本地主机名为host.domian.net,且在user表中有两项,一个Host值为localhost,而另一个为host.domian.net。带有localhost值的项仅当连接到localhost时才进行匹配,而另一项仅当连接到host.domian.net时才匹配。简言之,在Host中,localhost不等于主机名。
可以用通配符指定Host的值,可以使用SQL中的‘%’和‘_’,并与SQL查询中具有相同的含义。
2.User
user表示用户名,必须是常量或空值,空值表示任何用户。user列不支持通配符。在user表中,当MySQL找到与登录用户相配的项后,发现包含user为空值时,这个用户将被认为是匿名用户。
3.Password
Password代表用户口令,其值可以为空,不允许通配符,并以加密形式存储。空口令并非与任何口令相配,而是表示用户不必指定口令。
GRANT语句和mysqladmin password命令自动对口令进行加密,但使用INSERT、REPLACE、UPDATE或SETPASSWORD这样的语句来直接操作权限表时,则必须用PASSWORD(“NEW_PASSWORD”)来对输入的口令进行加密,而不能简单地使用“new_password”。
例如,下面使用GRANT命令创建账户super_user、db_user和tbl_user,分别在全局级、数据库级,以及表级上赋予查询数据的权利:
mysql> GRANT SELECT ON *.* TO super_user@localhost IDENTIFIED BY "my_password"; mysql> GRANT SELECT ON student_course.* TO db_user@localhost IDENTIFIED BY "my_password"; mysql> GRANT SELECT ON student_course.students TO tbl_user @localhost IDENTIFIED BY "my_password";
user表中相应添加的记录:
mysql>SELECT Host, User, password, Select_priv, Insert_priv FROM user WHERE user = 'super_user' OR user ='db_user' OR user = 'tbl_user'; +------------------- +------------------- +-------------------------- +-------------------+------------------- + |Host |User |password | Select_priv |Insert_priv | +------------------- +------------------- +-------------------------- +-------------------+------------------- + |localhost |super_user |4bec313a33935fce |Y |N | |localhost |db_user |4bec313a33935fce |N |N | |localhost |tbl_user |4bec313a33935fce |N |N | +------------------- +------------------- +-------------------------- +-------------------+------------------- +
可以发现,对于db_user和tbl_user,其Select_priv值仍旧是N,而不是Y。这是因为,所授的权限限定于某个数据库或某个表,而user表中记录控制所有数据库的全局权限。User表只有同下面所介绍的授权表一起,才能实现库级和表级权限。
★ 注意 ★
授权表中的记录是区分大小写的,如果把“super_user”写成了“Super_user”,则不会找到用户信息。
6.6.3 控制库级访问
MySQL使用db授权表控制数据库级别的访问权限。db表列出所有的数据库以及用户拥有访问这些数据库的权限,并且指定的权限适用于数据库中所有的表。db表的内容如表6-4所示。
表6-4 db授权表
其中,数据库(表)操作权限同user表的内容相同,指定来自客户端Host的用户User在Db数据库上所拥有的权限。
db表示所要控制权限的数据库,在columns_priv和tables_priv表中,db值必须是直接的数据库名,不允许通配符和空值。而在db和host表中,Db值可以用间接量,通过通配符‘%’或‘_’来指定%值或空值与任何数据库相配。
同样,在执行了上面的授权语句:
mysql> GRANT SELECT ON *.* TO super_user@localhost IDENTIFIED BY "my_password"; mysql> GRANT SELECT ON student_course.* TO db_user@localhost IDENTIFIED BY "my_password"; mysql> GRANT SELECT ON student_course.students TO tbl_user @localhost IDENTIFIED BY "my_password";
后,db表中所添加的相应信息:
mysql> SELECT Host, db, User, Select_priv, Insert_priv FROM db WHERE user = 'super_user' OR user ='db_user' OR user = 'tbl_user'; +------------------- +------------------- +------------------- +-------------------+------------------- + |Host |db | User |Select_priv |Insert_priv | +------------------- +------------------- +------------------- +-------------------+------------------- + |localhost |student_course| db_user |Y |N | +------------------- +------------------- +------------------- +-------------------+------------------- +
结果显示了具有库级权限的用户db_user的权限信息,与之对应的用户有:
(1)对于超级用户suer_user,因为其查询功能凌驾于所有数据库之上,在db表中并没有其信息;
(2)对于表级用户tbl_user,其查询功能仅仅限于某个表,其信息也未在db表中表现,而是需要使用到下面的table_priv表。
除db表之外,还有一个授权表host表,可以与db表结合使用,在更细的级别上控制对特定主机数据库的访问权限。但是,host表不受GRANT和REVOKE语句的影响,因此很少使用。
6.6.4 控制表级访问
table_priv表指定用户表级操作的权限,在其中所指定的权限适用于某个表。其结构信息如表6-5所示。
表6-5 table_priv授权表
这些列中的值必须是直接的表名或列名,不允许通配符和空白值。
对于表中的某些列,MySQL区分大小写,另一些则不然。但Table_name列始终是区分大小写的,即使SQL查询中的表名是取决于服务器运行的文件系统,MySQL也区分其大小(在UNIX文件系统区分大小写,而在Windows中不区分)。
在执行了授权语句:
mysql> GRANT SELECT ON student_course.students TO tbl_user @localhost IDENTIFIED BY "my_password";
后,tables_priv表中所添加的相应信息为:
mysql>SELECT * FROM tables_priv WHERE user='tbl_user'; Host Db User Table_name Grantor Timestamp Table_priv Column_priv Local Student tbl students ODBC@l 2006030214 Select Host _course _user ocalhost 3
可以看到,tbl_user用户在数据库student_course的students表上具有select权限,由于没有进一步限定其权限于某一列上,因此column_priv为空。
6.6.5 控制列级访问
columns_priv表指定用户列级的操作权限,在这里所指定的权限适用于表中特定的列。其属性信息如tables_priv基本一致,不同之处在于没有table_priv属性。
例如,使用下面的GRANT命令创建一个col_user,并指定其在students表的sname列上具有查询的权限:
mysql> GRANT SELECT(sname) ON student_course.students TO col_user @localhost;
columns_priv表的结果如:
mysql> SELECT * FROM columns_priv WHERE user = 'col_user'; +------------ +---------------+---------+-------------------+-------------------- +------------------- +---------------+ |Host |Db |User |Table_name |Column_name|Timestamp |Column_priv| +------------ +---------------+---------+-------------------+-------------------- +------------------- +---------------+ |localhost |student_course |col_user |students |sname |20060302153856 |Select| +------------ +---------------+---------+-------------------+-------------------- +------------------- +---------------+
6.6.6 一个应用示例
本节将通过示例,来说明如何手动使用授权表来完成GRANT和REVOKE所实现的用户及权限管理,实现思路如下。
(1)当提交GRANT语句时,需要指定用户名和主机号,可能还指定口令。此时,user表建立该用户,这些登录信息分别记录在其User、Host和Password列中,通过INSERT语句来实现。
(2)如果GRANT指定了数据库级的权限,用户名和主机名将记录在db表项的User和Host列中,所授权的数据库记录在Db列中,而所授予的权限记录在权限列中,同样可以使用INSERT语句来实现。表级和列级权限是类似的。
(3)当使用UPDATE直接修改授权表时,需要重新加载授权表,否则MySQL将不会知道权限的变化。可以通过执行mysqladmin flush-privileges或mysqladmin reload命令重新加载。如果忘记这步操作,服务器将不会刷新授权表。
示例1:建立超级用户
下面的grant语句将创建一个拥有全部权限的超级用户,其中包括向其他用户授权的能力:
GRANT ALL ON *.* TO super_user@localhost IDENTIFIED BY "my_password" WITH GRANT OPTION
该语句将创建user表的super_user@localhost的项,并开启所有的操作权限。用INSERT进行同样工作的语句是:
INSERT INTO user VALUES
('localhost','super_user',PASSWORD('my_password')),'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y',' Y','Y','Y','Y')
这个INSERT语句可不好写,这也就是GRANT语句存在的原因之一。
示例2:建立数据库级用户
下面的grant语句将创建一个拥有在数据库student_course上全部权限的用户,包括向其他用户授权的能力:
GRANT ALL ON student_course.* TO db_user@localhost IDENTIFIED BY "my_password" WITH GRANT OPTION
这些权限不是全局的,因此不能存储在user表中。但仍需要在user表中创建一项以保存该用户的登录信息,同时还需要创建一个db表中的项来记录数据库级的权限:
INSERT INTO user(host,user,password) VALUES('localhost','db_user',PASSWORD('my_password')); INSERT INTO db VALUES ('localhost','student_course','db_user','Y','Y','Y','Y','Y','Y','N','Y','Y','Y')
这个INSERT语句也不好写。
为了设置表级或列级权限,需要对tables_priv或columns_priv表使用INSERT语句即可,在些不再赘述。如果要想修改某个已经存在的用户的权限,无论是增加还是取消权限,应使用UPDATE而非INSERT语句。为删除一个用户,使用DELETE从该用户所在的每个授权表中删除其值。