1 一般安全问题
1.1 安全性指南
不仅需要考虑MySQL自身的安全性,主机和网络的安全性都是需要考虑的。下面是一些指南
- 保护好root权限,其他用户不要访问user表
- 理解MySQL的权限系统
- 不要存储和传输明文密码,不要使用字典密码
- 投资防火墙安全设备
- 过滤应用提交的数据
1.2 保护密码的安全
1.2.1 密码与日志
写在SQL语句中的明文密码,如create user,grant或调用了password()的语句,会被记录到日志中。
在5.6.3之后的版本,才对日志的密码进行了处理,除非出于调试目的,使用log-raw选项。这样能访问日志的用户也能得到数据库的用户密码。
日志最好进行保护,只给有权限的人看。
从库出于备份的目的,也会存储主库服务器的用户和密码,相应的配置文件也需要进行保护。
1.2.2 密码的散列
MySQL在user表中存储了密码的HASH值,这个值只在用户连接进来时进行检查,当用户连接验证后,可以更新自己的密码。
历史上4.1版本之前使用一种密码HASH算法,而4.1.1之后采用了另一种算法,如果需要兼容历史数据,可以设置服务器变量old_passwords=1,或者使用old_password()函数。
1.2.3 密码可用性插件
在5.6.6版本以后,提供了一个插件validate_password.so,它可以用来检查用户使用密码的健壮性。
1.3 攻击的防范
建议实施下列措施
所有用户必须使用密码登录
只有对数据库数据目录拥有读写权限的用户才可以运行服务器,不要用ROOT用户启动服务器
不要对非管理用户赋予FILE权限,防止此用户利用服务器进程的权限生成非法文件或读取敏感文件信息。
不要对非管理用户赋予PROCESS或SUPER权限,否则show processlist会泄露更新user表密码的数据
不要使用符号链接到表
如果DNS不可控,在授权时使用IP而不是域名
在授权时可以设置用户数据库访问的频率和次数
1.4 安全相关的选项与变量
名称
|
类型
|
含义
|
allow-suspicous-udfs
|
option
|
是否允许从共享库中加载用户自定义函数
|
automatic_sp_prileges
|
var
|
是否赋予存储过程创建者的执行和修改权限
|
chroot
|
option
|
设置chroot的路径
|
des-key-file
|
option
|
指定DES密钥的文件
|
local_infile
|
var
|
是否允许LOAD DATA支持LOCAL操作
|
safe-user-create
|
option
|
是否禁止带grant选项的用户创建用户,除非对user表可INSERT
|
secure-auth
|
option
|
是否禁止使用旧HASH算法密码的用户登录
|
secure-file-priv
|
option
|
指定和文件系统交互时允许的路径
|
skip-grant-tables
|
option
|
启动时不加载权限表
|
skip-name-resolve
|
|
|
skip-show-database
|
option
|
是否只允许SHOW DATABASE权限的人使用show database
|
1.5 以普通用户运行
将datadir目录权限设置为对普通用户如mysql来属主
修改配置文件中[mysqld]下的user=mysql
启动服务
1.6 LOAD DATA LOCAL的安全性
LOAD DATA可以加载服务器上的文件,增加LOCAL选项后则可以加载客户端上的文件。带LOCAL后存在两个安全隐患:一方面服务器可访问客户端能访问的所有文件,另一方面如果用户是通过WEB SERVER连接的,则LOCAL指定的CLIENT实现是WEB SERVER。
因而最好根据需求情况在服务器上设置local-infile选项和变量。
1.7 客户端编程安全性
核心问题是避免SQL的注入攻击。检查传入参数的类型及值。要点如下:
使用strict SQL模式
对于动态URL进行URL转义(escape)
当把数据传递给MySQL时,注意检查数据大小
应用程序的连接用户遵循最小权限原则
对于不同语言的API,选择正确的转义函数,并使用prepare机制
对于URL提交的数字都转义为字符,检查是否有问题
检查所有表单数据加上单引号和双引号时是否有问题
在数据域中输入其他字符、空格、特殊符号等,检查是否有问题
2 MySQL的访问控制系统
MySQL将用户的认证和权限信息存储在mysql数据库中,当启动时数据被加载到内存中,当后续用户连接或操作时,将用内存的数据进行验证。首先,当用户连接时,将验证用户的身份。其次,对于连接上的后续操作,将验证此用户是否拥有相应的权限。
可以通过show grants for some@host来查看查用户的授权信息。
2.1 权限级别
服务器级:用于用户管理整个MySQL服务器
DB级:针对单个库及库中的全体对象
对象级:针对库中的某个对象,如表、索引、视图等
所有的权限均在user表的定义中,*_priv字段描述了所有权限。下表描述了在SQL语句中可以使用的权限名称及含义。
权限定义
|
含义
|
ALL
|
所有权限的并
|
ALTER
|
修改表的权限,同时需要CREATE和INSERT权限
|
ALTER ROUTINE
|
|
CREATE
|
创建新数据库或表
|
CREATE ROUTINE
|
|
CREATE TABLESPACE
|
创建、修改、删除
|
CREATE TEMPORARY TABLES
|
创建临时表
|
CREATE USER
|
允许使用CREATE、DROP、重命名用户及回收权限
|
CREATE VIEW
|
允许创建视图
|
DELETE
|
允许删除表中的行
|
DROP
|
允许DROP数据库、表、视图
|
EVENT
|
|
EXECUTE
|
|
FILE
|
允许使用LOAD DATA INFILE和SELECT DATA OUTFILE
以访问服务器文件系统
|
GRANT OPTION
|
是否允许一个用户将自己的权限赋予或收回到其他用户
|
INDEX
|
是否允许创建或删除索引
|
INSERT
|
是否允许向数据表中插入数据
|
LOCK TABLES
|
是否允许锁定表
|
PROCESS
|
是否允许show process权限
|
PROXY
|
|
REFERENCES
|
未使用
|
RELOAD
|
是否允许FLUSH的各种操作
|
REPLICATION CLIENT
|
是否允许show master/slave/binary status
|
REPLICATION SLAVE
|
是否允许作为从库连接主库以复制数据
|
SELECT
|
是否允许从表中查询行,只有从表中获取行时才检查
|
SHOW DATABASES
|
|
SHOW VIEW
|
|
SHUTDOWN
|
|
SUPER
|
允许使用change master to ,kill,purge,set global命令
|
UPDATE
|
允许更新表中的行
|
USAGE
|
没有权限
|
2.2 授权系统表
系统使用下列表完成授权功能,可以直接查看这些表的定义来分析其作用。
表名
|
功能
|
user
|
包含用户帐户对应的全局权限信息
|
db
|
包含数据库级的权限,指示用户能操作的库的权限
|
host
|
已经删除
|
tables_priv
|
包含表级权限,指示用户能操作的表的权限
|
columns_priv
|
包含列级权限,指示用户对每个列的权限
|
procs_priv
|
包含存储过程和函数权限
|
proxies_priv
|
包含代理用户权限
|
2.3 指定帐户名
账户名分用户名和主机两部分,可以在create user或grant时指定some@host。需要注意的是,如果加引号的话@前后部分要分别引住,否则整体被解释为用户名部分。%可用在用户名或主机名的内部作为模式匹配来使用。对于IP地址,可以以形式ip/netmask来指定。
连接验证阶段,将验证用户的主机名和用户名,如果用户名未指定,则为匿名,会匹配user表中user为空的行。
连接时密码可为空,意味着用户可以不使用密码登录。
2.4 权限生效时机
如果使用grant,revoke,set,password,rename user命令,服务器会生动加载权限到内存中。
如果使用insert,update,delete修改权限表,则需要手动重新加载权限表,如flush privileges
3 MySQL的用户帐户管理
3.1 使用用户名和密码
mysql -u name -p db
mysql --user=name --password=pass db
3.2 添加用户示例
mysql>CREATE USER 'monty'@'localhost' IDENTIFIED BY 'some_pass';
mysql>GRANT ALL PRIVILEGES ON *.* TO 'monty'@'localhost'
WITH GRANT OPTION;
3.3 删除用户
使用drop user可删除用户。
3.4 设置用户资源限制
mysql>GRANT ALL ON test.* TO 'user'@'localhost'
->WITH MAX_QUERIES_PER_HOUR 20
->MAX_UPDATES_PER_HOUR 10
->MAX_CONNECTIONS_PER_HOUR 5
->MAX_USER_CONNECTIONS 2;
如果希望移除限制,将相应的值设置为0即可。
3.5 设置用户密码
可以使用create user和grant语句的identified by [password]子句来设置用户的密码。如果是直接使用密码的HASH,则需要使用password命令。
此外set password for user name = password('pass');
3.6 认证插件
MySQL提供了一系列的认证插件,通过插件提供的功能,可以使用不同的认证方式,如WINDOWS本地认证,PAM认证等等。
具体可以参考5.6参考手册的6.3.8节。