MySQL技术内幕——安全性与访问控制
安全性与访问控制
保护对MySQL文件系统的访问
如何窃取数据
- (1)在服务器主机上安装一个自己的"流氓"MySQL服务器,使用与官方服务器不同的端口,套接字文件和数据目录。
- (2)运行mysql_install_db,初始化数据目录。
此动作可让你以MySQL的root用户身份访问你的服务器,建立一个test数据库,用于存储窃取到的表。 - (3)访问你想攻击的服务器的数据目录,将想窃取的表对应的文件复制到你自己那个服务器数据目录下的test目录。
- (4)启动流氓服务器。
可通过SQL访问复制表的信息。 - (5)对"流氓"数据库不设权限。
外部用户通过"流氓"数据库来访问本无权限访问的内容
保护MySQL安装
- (1)停止MySQL服务器
% mysqladmin -p -u root shutdown
- (2)用以下命令,把整个MySQL安装的所有者和组名设为MySQL管理账户。
# chown -R mysql /usr/local/mysql
# chgrp -R mysql /usr/local/mysql
- (3)对客户端应能访问的基本目录及其子目录,需更改它们的模式,以便mysql拥有其全部权限.而其他人只有其读取和执行权限。
- (4)更改数据目录及其下面所有文件和子目录的访问模式,只允许mysql用户访问它们。
% chmod -R go-rwx /usr/local/mysql/data
[mysqld]
user=mysql
可以让以root身份执行服务器程序时,自动切换为mysql身份来执行。
保护Unix套接字文件
对客户端至 localhost 的连接,服务器使用的是Unix域套接字文件。
此套接字文件常允许被公开访问,以便客户端程序可使用它。
对此文件需要客户端需要的是执行权限。
[mysqld]
socket=/usr/local/mysql/mysql.sock
[client]
socket=/usr/local/mysql/mysql.sock
保护选项文件
使用选项文件有潜在风险。
- 如某个选项文件含有诸如MySQL账户名或密码类的敏感信息,则不要让其可公共读取。
- /etc/my.cnf 该文件常允许公共可读,因为它是一个用于指定全局客户端选项的地方。
不要把服务器的选项放入其中。 - 每个用户特有的 (user-specific) .my.cnf选项文件,应该隶属于它所在主目录对应的那个用户,且只可被此用户访问。
% chmod u=rw,go-rwx .my.cnf
- 其他选项文件则需根据它们的具体用途来设置其访问模式。
管理MySQL用户账户
数据库权限表。
- CREATE USER、DROP USER、RENAME USER
分别用于创建,删除和重命名MySQL账户。 - GRANT
用于指定账户权限(如账户不存在,则创建它们)。 - REVOKE
用于移除MySQL账户的权限。 - SET PASSWORD
用于分配账户的密码。 - SHOW GRANTS
用于显示账户所拥有的权限。
权限表 | 内容 |
---|---|
user | 可连接到服务器的用户,及它们的全局性权限 |
db | 数据库权限 |
tables_priv | 表权限 |
columns_priv | 列权限 |
procs_priv | 存储例程权限 |
proxies_priv | 代理用户权限 |
执行CREATE USER语句时,需指定一个账户名和可选的授权信息(密码或授权方法),服务器会在 user 表里为这个新账户创建一个行。
在GRANT语句时,指定账户不存在,会先将其创建。
在使用GRANT语句时,如果指定了全局权限,也会被记录到user表里。
如果在GRANT里指定的权限只适用于给定的数据库,表,列,存储例程,则它们会被分别记录到db,tables_priv,columns_priv或procs_priv表里。
PROXY权限的分配会被记录在proxies_priv表里。
REVOKE可删除权限表里的权限,DROP USER可从各个表中删除与给定账户相关的所有行。
MySQL账户的高级管理
指定账户名
在账户管理语句里,account值由用户名和主机名构成
具体格式为 ‘user_name’@‘host_name’ 。 (主机名为客户端所在的主机)
将账户名里的主机值与DNS相匹配
DNS解析返回的应该与账户指定的完全一致才匹配(匹配按字符串逐字符匹配进行的)。
指定账户认证方式
CREATE USER 语句可借助于可选的auth_info来指定账户认证方式:
CREATE USER account [auth_info]
auth_info子句可采用两种形式如下所示:
- 账户采用密码认证
- 指定一种不同的认证方法。
权限分配
为某个账户分配访问权限时,可用GRANT语句:
GRANT privileges [(columns)]
ON what
TO account [auth_info]
[REQUIRE encryption requirements]
[WITH grant or resource management options]
如果指定的账户存在,则GRANT会修改其权限。
如果指定的账户不存在,则GRANT会在创建它时带上分配的权限。
其中有几个子句是可选的,如无必要,完全可以不用指定它们。通常情况下,最为常用的是下面几个部分。
- privileges
表示分配给账户的权限 - columns
指定受权限影响的列。(xx,xxx, xx) 多个列必须以逗号隔开,并且需要列在括号里。 - what
表示权限应用的级别。
最高级别是全局级,其中的权限会应用到所有数据库和所有表。
也可指定应用到数据库、表、列、存储例程。 - account
表示被授予权限的账户。
格式为 ‘user_name’@‘host_name’ 。 - auth_info
表示账户密码或认证方法。 - REQUIRE
会设置账户,要求其在进行连接时需使用安全的安全套接字层连接。 - WITH
可用于授予GRANT OPTION权限,进而让账户能把自己的权限转授给其他用户。
定义账户的权限
一个账户可被授予多种权限。
主要分为两类:管理权限,对象权限。
两个特殊的权限说明符:ALL 和 USAGE。
ALL表示所有权限;
USAGE表示无权限。
- CREATE USER
此权限允许使用的语句含:CREATE USER 、DROP USER、RENAME USER、REVOKE ALL PRIVILEGES 。 - FILE
可让你告诉服务器读取或写入服务器主机的文件。 - GRANT OPTION
可让你将自己拥有的权限授予其他用户。 - PROCESS
MySQL服务器是多线程的,能够同时为多个客户连接提供服务。 - PROXY
使你能获得另一用户的权限。 - RELOAD
让你能执行某些服务器管理操作。
让你可执行FLUSH/RESET等;
还可执行reload、refresh、flush-hosts、flush-logs 等 mysqladmin命令。 - REPLICATION CLIENT
使你可使用SHOW MASTER STATUS、SHOW SLAVE STATUS来查询主、从服务器的位置和状态。 - SHOW DATABASES
查看所有数据库名称。 - SHUTDOWN
可让你关闭服务器。 - SUPER
此权限使你能够使用 KILL 语句或 mysqladmin kill 命令来终止服务器进程。 - ALTER
使你可执行ALTER TABLE xxx 。 - ALTER ROUTINE
使你能更改或删除存储函数和存储过程。 - CREATE
使你能创建数据库和表。 - CREATE ROUTINE
使你能创建存储函数和存储过程。 - CREATE TABLESPACE
使你能创建,删除,或更改表空间。 - CREATE TEMPORARY TABLES
创建临时表。 - CREATE VIEW
创建视图。 - DELETE
删除表里的行。 - DROP
删除数据库和表。 - EVENT
使你能对事件调度器的各个事件进行操作。 - EXECUTE
使你能执行存储函数和存储过程。 - INDEX
使你能创建或删除表的索引,为键缓存分配索引,将索引预加载到键缓存。 - INSERT
使你能将行插入到表。 - LOCK TABLES
锁定表。 - REFERENCES
此权限未使用。 - SELECT
检索表里的数据。 - SHOW VIEW
查看视图。 - TRIGGER
添加和删除触发器。 - UPDATE
修改表里的行。
权限级别:
权限说明符 | 权限作用级别 |
---|---|
ON . | 全局权限,所有数据库+所有表 |
ON * | 默认数据库 |
ON db_name.* | 指定数据库 |
ON db_name.tbl_name | 指定数据库的指定表 |
ON tbl_name | 指定表 |
ON db_name.routine_name | 指定数据库的指定例程 |
ON account | 代理权限 |
想显式地指定权限要应用的对象类型,可以含TABLE, FUNCTION, PROCEDURE(如ON TABLE xx.xx 或 ON FUNCTION xx.xx)。
USAGE权限只能全局级指定(ON .)。
ALL会把给定级别上所有权限授予账户。
ALL下的所有权限不会包含GRANT和REVOKE所需的GRANT OPTION。
- 使用无权限的USAGE权限
让你更改某个账户的特性,同时保证原有权限不受影响。 - 要求账户使用安全连接
- 让账户拥有管理权限
- 限制账户的资源占用
- 显示账户权限
SHOW GRANTS FOR 'sampadm'@'localhost';
SHOW GRANTS;
- 撤销权限
REVOKE。
REVOKE没有auth_info, REQUIRE, WITH子句。
REVOKE privileges [(columns)] ON what FROM account;
GRANT ALL ON sampdb.* TO 'boris'@'localhost';
REVOKE DELETE, UPDATE ON sampdb.* FROM 'boris'@'localhost';
要撤销某个权限,你需先自己拥有该权限,还需拥有GRANT OPTION权限。
- 更改密码或重置丢失的密码
- 插入式身份认证和代理用户
权限表结构和内容
各类权限管理SQL语句最终都变为对MySQL权限表的修改。
权限表控制着客户端对MySQL数据库的访问,位于mysql数据库里,会在将MySQL第一次安装至机器的过程中被初始化。
这些表的名字分别是:user、db、tables_priv、columns_priv、procs_priv、proxies_priv 。
服务器对它们的使用情况如下:
- user表列出的是可连接至服务器的各个用户账户,及每个用户所拥有的全局权限。
在user表里启用的所有权限都是全局权限,适用于所有数据库。
user表还包含用于身份认证的列,用于使用SSL建立安全连接的SSL选项列,用于防止给定账户独占该服务器的资源管理列。 - db表列出的是哪些账户对哪些数据库有权限。
此处授予的权限可应用于数据库内的所有对象(包括表,存储例程等)。 - tables_priv表列出的是各种表级别的权限。
此处指定的权限适用于表里的所有列。 - columns_priv表列出的是列级别的权限。
此处指定的权限适用于表中的特定列。 - procs_priv表包含的是适用于各种存储例程(存储函数,存储过程)的权限。
此处指定的权限适用于数据库里的特定例程。 - proxies_priv表表明哪些账户可称为其他账户的代理,并获得它们的权限。
每个权限表含两种基本类型的列:
一个是访问访问列,用于确定何时应用于行;另一个是权限列,用于确定某个行授予了哪些权限。
user表还有几个用于身份认证,SSL连接和资源管理的列。
权限系统包含的表有 tables_priv、columns_priv、procs_priv,分别用于定义以下各项的权限:特定表、列、存储函数和存储过程。
权限表访问范围列
当某个账户试图执行某个给定操作时,访问范围列的操作决定了服务器会使用哪些行来确定最终的权限。
权限表的每个行都包括Host列,User列,用于表明该行适用于由特定用户从给定主机发起的连接。
db表含一个Db列,用于表明该行适用于那个数据库。
tables_priv和columns_priv表的行里包含的访问范围列,使其访问范围进一步变窄,分别限定在数据库里的特定表和表里的特定列中。
procs_priv表的访问范围列则指定了一个行适用于那个存储函数或存储过程。
权限表权限列
对每一行,这些权限列表明的是,由访问范围列标识出的那个用户拥有哪些权限。
在user表和db表里,指定的每种权限都是一个单独列。这些列被定义为ENUM(‘N’, ‘Y’)类型,其默认值为’N’。
如,Select_priv列定义如下:
Select_priv ENUM('N', 'Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N'
表tables_priv, columns_priv, procs_priv里的权限都是用SET表示的,从而可将存储在同一列的各种权限任意组合。
SET('Select','Insert',...,'Trigger')
CHARACTER SET utf8 NOT NULL DEFAULT ''
columns_priv表的Column_priv列的定义如下:
SET
('Select',...)
CHARACTER SET utf8 NOT NULL DEFAULT ''
权限表身份认证列
user表有3个用于指明账户认证方式的列:Password、plugin、authentication_string 。
对某个给定账户在user表里对应的行,如果 plugin 列为空,则客户端进行账户认证时会使用Password列里的密码。
权限表SSL相关列
在user表里,有几个列适用于基于SSL的安全认证。
最主要的列是ssl_type,它表明账户是否需要安全连接。
服务器如何控制客户端访问
MySQL服务器对客户端的访问控制分为两个阶段。
-
第一阶段在你试图连接服务器的时候。
-
第二阶段,服务器会对执行的每一条语句作两项检查。
首先,它检查每小时执行语句数目和每小时更新数目的限制。
其次,服务器会检查权限表,以验证你是否有足够的执行该语句的访问权限。
访问范围列的内容
每个访问范围列都有一些约束规则,来定义哪些类型值是合法的,及服务器会如何解释它们。
- Host
主机名、IP地址。值 localhost 代表本地主机。 - User
用户名必须为文字值或空白(空)。空白值可以匹配任何名字,即为“匿名”。否则,它必须与指定的名字精确匹配。 - Db
在 db 表里,指定 Db 值时,可以使用普通字符,也可以使用 SQL 模式字符 “%”或“_” 指定的通配符。 - Table_name,Column_name和Routine_name
这些列值必须分别为普通的表名、列名或存储例程名。
列值需要与指定的名字精确匹配。不允许使用模式和空白值。 - Routine_type
此列的值只能是 ‘FUNCTION’ 或者 ‘PROCEDURE’ ,用来表示行中 Routine_name 列里的名字是适用于存储函数,还是适用于存储过程。 - Proxied_host,Proxied_user
这两列存在于 proxies_priv 表中,该表还拥有可以表示代理用户账户的 Host 列和 User 列。
学习参考资料:
《MySQL技术内幕》第5版