详解Mysql安全配置
时间:2016-05-14 12:08 来源:linux.it.net.cn 作者:IT
目录
1. 前言
2. Mysql账户权限安全
3. Mysql数据的网络安全配置
4. 密码策略安全
5. Mysql日志
6. Mysql数据库服务所在主机安全配置
7. 部署SQL注入检测、防御模块
8. mysqld安全相关启动选项
9. mysql备份策略
1. 前言
Mysql数据库安全配置、或者叫加固属于风险模型中的一环,它需要安全人员在理论和实践的学习中不断发现新的问题,并针对这些问题对数据的各个方面的配置进行强化。本文试图围绕着数据库风险识别、数据库安全加固这个问题,探讨可以采取的措施来最大程度的保证我们的数据库的安全控制处在一个较好的水平。
2. Mysql账户权限安全
mysql中存在4个控制权限的表,分别为
1. mysql.USER表
2. mysql.DB表
3. mysql.TABLES_PRIV表
4. mysql.COLUMNS_PRIV表
要注意的是,Mysql中有一个数据库”information_schema”,似乎里面保存的也是一些权限信息,但是要明白的是,这个数据库”information_schema”是为系统管理员提供元数据的一个简便方式,它实际上是一个视图,可以理解为对Mysql中的一个信息的封装,对于Mysql主程序来说,身份认证和授权的信息的来源只有一个,就是”mysql”。
http://www.cnblogs.com/hzhida/archive/2012/08/08/2628826.html
0×1. mysql.USER表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
select
*
from
USER
;
desc
USER
;
mysql>
desc
USER
;+
------------------------+-----------------------------------+------+-----+---------+-------+
| Field | Type |
Null
|
Key
|
Default
| Extra |
+
------------------------+-----------------------------------+------+-----+---------+-------+
| Host |
char
(60) |
NO
| PRI | | |
|
User
|
char
(16) |
NO
| PRI | | |
|
Password
|
char
(41) |
NO
| | | |
| Select_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Insert_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Update_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Delete_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Drop_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Reload_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Shutdown_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Process_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| File_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Grant_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| References_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Index_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Alter_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Show_db_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Super_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_tmp_table_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Lock_tables_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Execute_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Repl_slave_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Repl_client_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_view_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Show_view_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_routine_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Alter_routine_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_user_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Event_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Trigger_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_tablespace_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| ssl_type | enum(
''
,
'ANY'
,
'X509'
,
'SPECIFIED'
) |
NO
| | | |
| ssl_cipher | blob |
NO
| |
NULL
| |
| x509_issuer | blob |
NO
| |
NULL
| |
| x509_subject | blob |
NO
| |
NULL
| |
| max_questions |
int
(11) unsigned |
NO
| | 0 | |
| max_updates |
int
(11) unsigned |
NO
| | 0 | |
| max_connections |
int
(11) unsigned |
NO
| | 0 | |
| max_user_connections |
int
(11) unsigned |
NO
| | 0 | |
| plugin |
char
(64) | YES | | | |
| authentication_string | text | YES | |
NULL
| |
| password_expired | enum(
'N'
,
'Y'
) |
NO
| | N | |
+
------------------------+-----------------------------------+------+-----+---------+-------+
0×2. mysql.DB表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
select
*
from
DB;
desc
DB;
mysql>
desc
DB; +
-----------------------+---------------+------+-----+---------+-------+
| Field | Type |
Null
|
Key
|
Default
| Extra |
+
-----------------------+---------------+------+-----+---------+-------+
| Host |
char
(60) |
NO
| PRI | | |
| Db |
char
(64) |
NO
| PRI | | |
|
User
|
char
(16) |
NO
| PRI | | |
| Select_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Insert_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Update_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Delete_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Drop_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Grant_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| References_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Index_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Alter_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_tmp_table_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Lock_tables_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_view_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Show_view_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Create_routine_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Alter_routine_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Execute_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Event_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
| Trigger_priv | enum(
'N'
,
'Y'
) |
NO
| | N | |
+
-----------------------+---------------+------+-----+---------+-------+
0×3. mysql.TABLES_PRIV表
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
select
*
from
TABLES_PRIV;
desc
TABLES_PRIV;
mysql>
desc
TABLES_PRIV;
+
-------------+-----------------------------------------------------------------------------------------------------------------------------------+------+-----+-------------------+-----------------------------+
| Field | Type |
Null
|
Key
|
Default
| Extra |
+
-------------+-----------------------------------------------------------------------------------------------------------------------------------+------+-----+-------------------+-----------------------------+
| Host |
char
(60) |
NO
| PRI | | |
| Db |
char
(64) |
NO
| PRI | | |
|
User
|
char
(16) |
NO
| PRI | | |
| Table_name |
char
(64) |
NO
| PRI | | |
| Grantor |
char
(77) |
NO
| MUL | | |
|
Timestamp
|
timestamp
|
NO
| |
CURRENT_TIMESTAMP
|
on
update
CURRENT_TIMESTAMP
|
| Table_priv |
set
(
'Select'
,
'Insert'
,
'Update'
,
'Delete'
,
'Create'
,
'Drop'
,
'Grant'
,
'References'
,
'Index'
,
'Alter'
,
'Create View'
,
'Show view'
,
'Trigger'
) |
NO
| | | |
| Column_priv |
set
(
'Select'
,
'Insert'
,
'Update'
,
'References'
) |
NO
| | | |
+
-------------+-----------------------------------------------------------------------------------------------------------------------------------+------+-----+-------------------+-----------------------------+
0×4. mysql.COLUMNS_PRIV表
select
*
from
COLUMNS_PRIV;
desc
COLUMNS_PRIV;
mysql>
desc
COLUMNS_PRIV; +
-------------+----------------------------------------------+------+-----+-------------------+-----------------------------+
| Field | Type |
Null
|
Key
|
Default
| Extra |
+
-------------+----------------------------------------------+------+-----+-------------------+-----------------------------+
| Host |
char
(60) |
NO
| PRI | | |
| Db |
char
(64) |
NO
| PRI | | |
|
User
|
char
(16) |
NO
| PRI | | |
| Table_name |
char
(64) |
NO
| PRI | | |
| Column_name |
char
(64) |
NO
| PRI | | |
|
Timestamp
|
timestamp
|
NO
| |
CURRENT_TIMESTAMP
|
on
update
CURRENT_TIMESTAMP
|
| Column_priv |
set
(
'Select'
,
'Insert'
,
'Update'
,
'References'
) |
NO
| | | |
+
-------------+----------------------------------------------+------+-----+-------------------+-----------------------------+
以上是这4个表的基本结构,在我们进行数据库连接、登录的时候,mysql权限表的验证过程为:
1. 先从user表中的:
1) Host
2) User
3) Password
这3个字段中判断连接的ip、用户名、密码是否存在,存在则通过验证。
2. 通过身份认证后,进行权限分配,按照:
1) user
2) db
3) tables_priv
4) columns_priv
的顺序进行验证。
即先检查全局权限表user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,将不再检查db,tables_priv,columns_priv
如果全局权限表user对应的权限为N,则到db表中检查此用户对应的具体数据库,并得到db中为Y的权限
如果db中为N,则检查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推。逐级下降
用流程图表示如下:
了解了Mysql的账户权限原理和判断流程,我们接下来需要了解就是应该以怎样的方式去进行权限配置,才能达到所谓的”最小权限原则”呢?Mysql的账户权限优先级顺序是:
user->db->tables_priv->columns_pri
稍作思考,我们可以发现,这些表的作用本质上是一样的,区别就在于它们的作用域范围不同,从user到columns_pri逐级作用域范围降低,因此控制粒度也增大,它们的配置遵循”就近原则”,即以优先级最低的那个为准,所以,我们在进行Mysql的账户权限安全配置的时候会发现”我们似乎在做很多重复性的工作”。但我们要明白的,Mysql的这种逐层次的权限配置体系为我们提供了一个细粒度的控制方法。所以我们的权限配置也应该按照这个顺序来有规划地进行。
0×1. USER表
权限
权限级别
权限说明
最佳安全实践: 网站使用账户是否给予
CREATE
数据库、表或索引
创建数据库、表或索引权限
建议给与,安装WEB系统时需要创建表
DROP
数据库或表
删除数据库或表权限
建议给与
GRANT OPTION
数据库、表或保存的程序
赋予权限选项
不建议给与
REFERENCES
数据库或表
无
不建议给与
ALTER
表
更改表,比如添加字段、索引等
建议给与
DELETE
表
删除数据权限
建议给与
INDEX
表
索引权限
建议给与
INSERT
表
插入权限
建议给与
SELECT
表
查询权限
建议给与
UPDATE
表
更新权限
建议给与
CREATE VIEW
视图
创建视图权限
建议给与
SHOW VIEW
视图
查看视图权限
建议给与
ALTER ROUTINE
存储过程
更改存储过程权限
不建议给与
CREATE ROUTINE
存储过程
创建存储过程权限
不建议给与
EXECUTE
存储过程
执行存储过程权限
不建议给与
FILE
服务器主机上的文件访问
文件访问权限
不建议给与,防止因为注入导致的隐私文件泄漏
CREATE TEMPORARY TABLES
服务器管理
创建临时表权限
不建议给与,防止借助临时表发动的二次注入
LOCK TABLES
服务器管理
锁表权限
不建议给与
CREATE USER
服务器管理
创建用户权限
不建议给与
PROCESS
服务器管理
查看进程权限
不建议给与
RELOAD
服务器管理
执行flush-hosts, flush-logs, flush-privileges, flush-status, flush-tables, flush-threads, refresh, reload等命令的权限
不建议给与
REPLICATION CLIENT
服务器管理
复制权限
不建议给与
REPLICATION SLAVE
服务器管理
复制权限
不建议给与
SHOW DATABASES
服务器管理
查看数据库列表权限
不建议给与
SHUTDOWN
服务器管理
关闭数据库权限
不建议给与
SUPER
服务器管理
执行kill线程权限
不建议给与
从表格中可以看到,USER表主要针对数据库的账户进行粗粒度的权限控制,定义了”某人允许做什么事”。
0×2. DB表
权限
说明
网站使用账户是否给予
Select
可对其下所有表进行查询
建议给予
Insert
可对其下所有表进行插入
建议给予
Update
可对其下所有表进行更新
建议给予
Delete
可对其下所有表进行删除
建议给予
Create
可在此数据库下创建表或者索引
建议给予
Drop
可删除此数据库,及此数据库下的表
不建议给予
Grant
赋予权限选项
不建议给予
References
未来MySQL特性的占位符
不建议给予
Index
可对其下的所有表进行索引
建议给予
Alter
可对其下的所有表进行更改
建议给予
Create_tmp_table
创建临时表
不建议给予
Lock_tables
可对其下所有表进行锁定
不建议给予
Create_view
可在此数据下创建视图
建议给予
Show_view
可在此数据下查看视图
建议给予
Create_routine
可在此数据下创建存储过程
不建议给予
Alter_routine
可在此数据下更改存储过程
不建议给予
Execute
可在此数据下执行存储过程
不建议给予
Event
可在此数据下创建事件调度器
不建议给予
Trigger
可在此数据下创建触发器
不建议给予
DB表可以看成是USER表对权限控制的一个补充,一个更细粒度地、针对数据库库级别的权限控制。
同时,DB表也隐式包含了将账户限定在某个数据库的范围内这个配置,即限制某个用户只能用对它自己的数据库的控制权,对不属于它的数据库禁止操作,这能有效防止横向越权的发生。
mysql> select host,db,user from db;
+——+———+——+
| host | db | user |
+——+———+——+
| % | test | |
| % | test\_% | |
+——+———+——+
可以看到,user字段为空,表示当前不对用户做任何数据库属权限制,在网站的部署过程中,应该单独针对网站建立一个账户一个独立的数据库,并为这个账户分配唯一的专属数据库,防止网络被入侵后的横向、纵向提权。
对于Mysql中的账户权限相关的安全配置,总结如下:
1. 针对每个网站建立一个单独的账户
2. 为每个网站单独建立一个专属数据库(虽然DEDE、DZ普通采用表前缀的方法来实现”一库多站”,但好的做法还是”一库一站”)
3. 按照user->db->tables_priv->columns_pri的顺序进行细粒度的权限控制
4. 为每个用户单独配置一个专属数据库,保证当前用户的所有操作只能发生在它自己的数据库中,防止SQL注入发生后,黑客通过注入点访问到系统表
账户权限安全配置需要的常用命令
1. 新建一个用户并给予相应数据库的权限
grant select,insert,update,delete,create,drop privileges on database.* to user@localhost identified by ‘passwd’;
grant all privileges on database.* to user@localhost identified by ‘passwd’;
2. 刷新权限
flush privileges;
3. 显示授权
show grants;
4. 移除授权
revoke delete on *.* from ‘user’@’localhost’;
5. 删除用户
drop user ‘user’@’localhost’;
6. 给用户改名
rename user ‘jack’@’%’ to ‘jim’@’%’;
7. 给用户改密码
SET PASSWORD FOR ‘root’@’localhost’ = PASSWORD(‘123456’);
3. Mysql数据的网络安全配置
对数据库所在的DMZ的网络拓朴的安全配置也是我们在进行安全评估的时候需要考虑的一个方面,这对防御内网扫描、网络攻击有一定帮助。
0×1: 限制访问Mysql端口的IP
对Mysql的访问IP的限制,可以从应用层和主机层来分别达到目的
1. 主机层:
1) windows可以通过windows防火墙
2) Linux下可以通过iptables
来限制允许访问mysql端口的IP地址
//只允许指定的IP进行访问
iptables -A INPUT -p tcp -s xxxx.xxxx.xxxx.xxxx/24 –dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s xxxx.xxxx.xxxx.xxxx/24 –dport 3306 -j ACCEPT
..
iptables -P INPUT DROP
可以看到,这种方法的缺点是硬编码导致灵活性低,如果mysql的默认端口3306被修改了(例如8890),则这条iptables规则也需要相应的修改
1
2
3
4
5
6
7
8
9
mysql>
select
host,user,password from user;
+-----------+------+-------------------------------------------+
| host | user | password |
+-----------+------+-------------------------------------------+
| localhost | root | *832EB84CB764129D05D498ED9CA7E5CE9B8F83EB |
| . | root | *832EB84CB764129D05D498ED9CA7E5CE9B8F83EB |
| :: | root | *832EB84CB764129D05D498ED9CA7E5CE9B8F83EB |
| localhost | | |
+-----------+------+-------------------------------------------+
这几行记录表明了root这个账户只能是本机登录,在部署的过程中,我们可以为指定账户添加某个安全的跳板机,并保证这个跳板机IP是不变的。
0×2: 修改mysql的端口
windows下可以修改配置文件my.ini来实现,linux可以修改配置文件my.cnf来实现。
port = 3306
对mysql端口的修改可以从一定程度上防止端口扫描工具的扫描。
0×3: 限制连接用户的数量
数据库的某用户多次远程连接,会导致性能的下降和影响其他用户的操作,有必要对其进行限制。可以通过限制单个账户允许的连接数量来实现,设置my.cnf 文件的mysqld中的max_user_connections变量来完成。GRANT语句也可以支持资源控制选项来限制服务器对一个账户允许的使用范围。
#vi /etc/my.cnf
[mysqld]
max_user_connections 2
4. 密码策略安全
这里所谓的密文策略安全包括Mysql自身的账户密码的安全、也包括网站用户的密码安全。
0×1: mysql账户密码
因为mysql本身没有抗穷举的帐号锁定机制,所以对于mysql自身的登录帐号,尤其是root帐号,需要遵循”密码强度策略”设置高强度的密码,保证攻击者从穷举帐号攻击这条路无法获得合适的投资收益比。
0×2: 网站用户的密码
数据库管理员无法规定用户的网站使用什么样的密码策略,这完全取决于用户自己的编码习惯、或者说是站长所使用的CMS的编码习惯。这方面,mysql无法做的更多,但也许可以做的是建立一个针对网站密码穷举、脱库攻击的日志追溯系统,当发生脱库攻击时能第一时间给用户提供”事发现场”的更多信息。或者数据库管理员主动进行可控的撞库测试,提前帮助用户发生潜在的撞库、脱库风险。
5. Mysql日志
启动Mysql的日志不仅可以为我们提供性能热点的分析,还可以帮助我们加固Mysql数据库的安全,例如:
1. 从日志中获得典型SQL注入语句
2. 利用正则模型从日志中捕获注入攻击的发生
3. 在脱库、数据泄漏之后获得关于受攻击数据库的情况、泄漏范围等数据
mysql有以下几种日志,它们都在my.ini中进行配置:
1. 错误日志:-log-err
log-error=E:/wamp/logs/mysql_error.log
2. 查询日志(记录所有SQL语句):-log
log=E:/wamp/logs/mysql.log
3. 慢查询日志:-log-slow-queries
1) 查看慢查询时间
show variables like “long_query_time”;默认10s
2) 查看慢查询配置情况
show status like “%slow_queries%”;
3) 查看慢查询日志路径
show variables like “%slow%”;
//存储位置、长SQL的阈值
E:\wamp\bin\mysql\mysql5.6.12\data\LittleHann-PC-slow.log
long_query_time=5
4. 更新日志:-log-update
5. 二进制日志:-log-bin//记录除select语句之外的所有sql语句到日志中,可以用来恢复数据文件log-bin=E:/wamp/logs/bin
查看日志开启情况:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
show variables like
'log_%'
;
+----------------------------------------+----------------------------------------------------+
| Variable_name | Value |
+----------------------------------------+----------------------------------------------------+
| log_bin | ON |
| log_bin_basename | E:\wamp\bin\mysql\mysql5.6.12\data\mysql-bin |
| log_bin_index | E:\wamp\bin\mysql\mysql5.6.12\data\mysql-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| log_error | E:\wamp\logs\mysql.log |
| log_output | FILE |
| log_queries_not_using_indexes | OFF |
| log_slave_updates | OFF |
| log_slow_admin_statements | OFF |
| log_slow_slave_statements | OFF |
| log_throttle_queries_not_using_indexes | 0 |
| log_warnings | 1 |
+----------------------------------------+----------------------------------------------------+
6. Mysql数据库服务所在主机安全配置
安全问题是一个综合的纵深问题,Mysql的安全配置和所在系统(*iux、windows)的安全配置密切相关。
0×1: mysql进程运行账号
所谓”mysql进程运行账户”,即以什么样的身份权限来启动mysqld这个服务进程的。对于操作系统来说,每一个进程都有一个对应的”进程运行帐号”,这个进程运行帐号决定了这个应用程序可以获得哪些操作系统的权限。
1. 在windows下禁止使用local system(nt authority\system)来运行mysql账户,可以考虑使用network service或者自己新建一个windows账号,但是必须给与mysql程序所在目录的读取权限和data目录的读取和写入权限
2. 在linux下,新建一个mysql账号,并在安装的时候就指定mysql以mysql账户来运行,给与程序所在目录的读取权限,data所在目录的读取和写入权限。
0×2: mysql运行账号的磁盘权限
对mysql运行帐号的磁盘权限的配置,就是在进行ACL的配置(文件夹右键->属性->安全),对于ACL的配置,我们需要牢记的是”默认禁止原则”,即操作系统会默认对没有明确指示的权限设定为禁止,即假如你给一个用户授予了某个文件夹的读权限,那么它只有读权限,而不会拥有写权限(权限继承不考虑在内)。
对于mysql运行张厚啊的磁盘ACL配置,我们可以遵循以下原则
1. mysql运行账号需要给予程序所在目录的读取权限,以及data目录的读取和写入权限,保证mysql的正常运行
2. 不容许给予其他目录的写入和执行权限,特别是有网站的,这可以有效防御针对mysql的提权、或者webshell提权
1) udf提权
2) 系统关键目录、注册表写入启动文件
3. 取消mysql运行账户对于cmd,sh等一些程序的执行权限,这可以防御当mysql核心帐号被黑客获取后进一步提权
1) root账户被泄露
由于对cmd、sh等关键程序进行了权限控制,黑客无法继续深入操作系统提权
0×3: Chrooting
Chroot是Unix/类Unix的一种手段,它的建立会将其与主系统几乎完全隔离,也就是说,一旦遭到什么问题,也不会危及到正在运行的主系统。这是一个非常有效的办法,特别是在配置网络服务程序的时候。
0×4: 删除历史命令记录
历史命令记录是一种测信道数据泄漏,从某种程序上来说,”历史命令记录”就像种植在系统上的一个键盘记录rootkit,如果黑客获取到了目标服务器的webshell,就可以通过阅读“历史命令记录”来获取到大量的管理员操作记录,包括帐号和密码。
这些历史文件包括:
1. ~/.bash_history
2. ~/.mysql_history
..
cat /dev/null > ~/.bash_history
cat /dev/null > ~/.mysql_history
0×5: mysql.sock安全配置
默认情况下,PHP支持使用socket方式和msyql数据库进行通信,换句话来说,这也意味着,在服务器本机可以允许无密码直接登录mysql,请看下面的一段实例代码:
1
2
3
4
5
6
7
8
<?php
ini_set
(
"mysql.default_socket = /var/lib/mysql/mysql.sock"
);
$sql
=
"select user();"
;
$res
= mysql_query(
$sql
);
$final
= mysql_fetch_array(
$res
);
die
(var_dump(
$final
));
?>
执行成功,result:
array(2) { [0]=> string(16) “apache@localhost” [“user()”]=> string(16) “apache@localhost” }
这意味着黑客在获取了目标服务器的webshell之后,可以在不知道mysql帐号密码的情况下直接从数据库中获取隐私数据。
防御的方法还是一样,针对mysql程序帐号进行磁盘ACL控制,防止mysql越权读/写/执行非mysql目录下的文件。
7. 部署SQL注入检测、防御模块
根据OWASP2013的报告显示,针对数据库的攻击方式,SQL注入依然是主要的因素,因此针对SQL Injection的攻击,除了针对应用层的代码安全审计、SDLC之外,在数据库层部署数据库防火墙也应该作为纵深防御的一个手段。
目前基于SQL注入检测、防御的的数据库防火墙大概有以下几个:
1. 安华金和数据库防火墙系统(Xsecure-DBFirewall)
2. Snort入侵检测系统
能针对指定端口进行正则特征匹配方式的SQL注入检测
3. Java/J2EE 过滤器
对于J2ee的WEB应用来说,可以在HTTP请求上部署过滤器,并将SQL注入检测规律写在过滤器中
4. druid-sql-wall开源SQL检测、阻断系统
8. mysqld安全相关启动选项
1. –local-infile[={0|1}]
如果用–local-infile=0启动服务器,则客户端不能使用LOCAL in LOAD DATA语句,防止基于注入的直接文件读取数据泄漏
2. –old-passwords
强制服务器为新密码生成短(pre-4.1)密码哈希。当服务器必须支持旧版本客户端程序时,为了保证兼容性这很有用。
3. (OBSOLETE) –safe-show-database
1) 在MySQL 5.1以前版本的MySQL中,该选项使SHOW DATABASES语句只显示用户具有部分权限的数据库名
2) 在MySQL 5.1中,该选项不再作为现在的 默认行为使用,有一个SHOW DATABASES权限可以用来控制每个账户对数据库名的访问。
4. –safe-user-create
如果启用,用户不能用GRANT语句创建新用户,除非用户有mysql.user表的INSERT权限。如果你想让用户具有授权权限来创建新用户,你应给用户授予下面的权限:
mysql> GRANT INSERT(user) ON mysql.user TO 'user_name'@'host_name’;这样确保用户不能直接更改权限列,必须使用GRANT语句给其它用户授予该权限。
5. –secure-auth
不允许鉴定有旧(pre-4.1)密码的账户。
6. –skip-grant-tables
这个选项导致服务器根本不使用权限系统。这给每个人以完全访问所有的数据库的权力,这个选项常常在发生了忘记了msyql密码的情况使用这个方式在本机”无密码登录mysql”通过执行mysqladmin flush-privileges或mysqladmin eload命令,或执行FLUSH PRIVILEGES语句,你能告诉一个正在运行的服务器再次开始使用授权表。
7. –skip-name-resolve
主机名不被解析。所有在授权表的Host的列值必须是IP号或localhost
8. –skip-networking
在网络上不允许TCP/IP连接。所有到mysqld的连接必须经由Unix套接字进行
9. –skip-show-database
使用该选项,只允许有SHOW DATABASES权限的用户执行SHOW DATABASES语句,该语句显示所有数据库名。不使用该选项,允许所有用户执行SHOW DATABASES,但只显示用户有SHOW DATABASES权限或部分数据库权限的数据库名。请注意全局权限指数据库的权限。
9. mysql备份策略
像mysql、sqlserver、access这种数据库都是将数据以单独文件的形式保存在磁盘上的,所以,对于数据库的备份也可以采用传统的文件备份策略。总的来说,有以下方式:
1. 本地备份
使用mysqldump进行备份非常简单,在备份数据库的时候,我们还可以同时使用管道gzip命令对备份文件进行压缩,可以采用Rsync的异地备份方式方式,将备份服务器的目录挂载到数据库服务器,将数据库文件备份打包后,通过crontab定时备份数据:
备份数据使用命令:
#!/bin/sh
time=`date +”(“%F”)”%R`
$/usr/local/mysql/bin/mysqldump -u root -p111 database_backup | gzip > /home/zhenghan/mysql/mysql_backup.$time.gz
# crontab -l
# m h dom mon dow command00 00 * * * /home/zhenghan/mysql/backup.sh
恢复数据使用命令:
gzip -d mysql_backup.\(2014-06-17\)00\:00.gz
mysql_backup.(2014-06-17)00:00#mysql –u root -p111 < /home/zhenghan/mysql/mysql_backup.\(2014-06-17\)00\:00
2. 网络备份
3. MySQL本身自带的mysqldump备份
使用mysqldump可以把整个数据库装载到一个单独的文本文件中。这个文件包含有所有重建您的数据库所需要的SQL命令。这个命令取得所有的模式(schema)并且将其转换成DDL语法(CREATE语句,即数据库定义语句),取得所有的数据,并且从这些数据中创建INSERT语句。这个工具将您的数据库中所有的设计倒转。因为所有的东西都被包含到了一个文本文件中。这个文本文件可以用一个简单的批处理和一个合适SQL语句导回到MySQL中。
4. 直接复制数据库文件的备份形式
直接拷贝数据文件最为直接、快速、方便,但缺点是基本上不能实现增量备份。为了保证数据的一致性,需要在备份文件前,执行以下SQL语句:FLUSH TABLES WITH READ LOCK;也就是把内存中的数据都刷新到磁盘中,同时锁定数据表,以保证拷贝过程中不会有新的数据写入。这种方法备份出来的数据恢复也很简单,直接拷贝回原来的数据库目录下即可。
相关学习资料
http://drops.wooyun.org/tips/2245
http://www.cnblogs.com/siqi/archive/2012/11/21/2780966.html
http://hi.baidu.com/liveinyc/item/08d5e71cfb2872416926bb84
http://blog.chinaunix.net/uid-16728139-id-3683449.html
http://linux.chinaunix.net/techdoc/database/2008/01/14/976546.shtml
http://www.cnblogs.com/yuwensong/archive/2013/03/26/2981965.html
http://hi.baidu.com/xmflycat/item/7567e3c37c43ba57bcef6951
http://www.jb51.net/article/30319.htmhttp://hi.baidu.com/schyman/item/cd0884f5cb85af49922af2b8
from:http://www.2cto.com/Article/201406/310418.html
(责任编辑:IT)
目录
1. 前言
2. Mysql账户权限安全 3. Mysql数据的网络安全配置 4. 密码策略安全 5. Mysql日志 6. Mysql数据库服务所在主机安全配置 7. 部署SQL注入检测、防御模块 8. mysqld安全相关启动选项 9. mysql备份策略
1. 前言
1. mysql.USER表
2. mysql.DB表 3. mysql.TABLES_PRIV表 4. mysql.COLUMNS_PRIV表 要注意的是,Mysql中有一个数据库”information_schema”,似乎里面保存的也是一些权限信息,但是要明白的是,这个数据库”information_schema”是为系统管理员提供元数据的一个简便方式,它实际上是一个视图,可以理解为对Mysql中的一个信息的封装,对于Mysql主程序来说,身份认证和授权的信息的来源只有一个,就是”mysql”。
http://www.cnblogs.com/hzhida/archive/2012/08/08/2628826.html
0×1. mysql.USER表
0×2. mysql.DB表
0×3. mysql.TABLES_PRIV表
以上是这4个表的基本结构,在我们进行数据库连接、登录的时候,mysql权限表的验证过程为:
1. 先从user表中的:
1) Host 2) User 3) Password 这3个字段中判断连接的ip、用户名、密码是否存在,存在则通过验证。 2. 通过身份认证后,进行权限分配,按照: 1) user 2) db 3) tables_priv 4) columns_priv 的顺序进行验证。 即先检查全局权限表user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,将不再检查db,tables_priv,columns_priv 如果全局权限表user对应的权限为N,则到db表中检查此用户对应的具体数据库,并得到db中为Y的权限 如果db中为N,则检查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推。逐级下降
用流程图表示如下:
user->db->tables_priv->columns_pri
稍作思考,我们可以发现,这些表的作用本质上是一样的,区别就在于它们的作用域范围不同,从user到columns_pri逐级作用域范围降低,因此控制粒度也增大,它们的配置遵循”就近原则”,即以优先级最低的那个为准,所以,我们在进行Mysql的账户权限安全配置的时候会发现”我们似乎在做很多重复性的工作”。但我们要明白的,Mysql的这种逐层次的权限配置体系为我们提供了一个细粒度的控制方法。所以我们的权限配置也应该按照这个顺序来有规划地进行。
从表格中可以看到,USER表主要针对数据库的账户进行粗粒度的权限控制,定义了”某人允许做什么事”。
DB表可以看成是USER表对权限控制的一个补充,一个更细粒度地、针对数据库库级别的权限控制。
mysql> select host,db,user from db;
+——+———+——+ | host | db | user | +——+———+——+ | % | test | | | % | test\_% | | +——+———+——+
可以看到,user字段为空,表示当前不对用户做任何数据库属权限制,在网站的部署过程中,应该单独针对网站建立一个账户一个独立的数据库,并为这个账户分配唯一的专属数据库,防止网络被入侵后的横向、纵向提权。
1. 针对每个网站建立一个单独的账户
2. 为每个网站单独建立一个专属数据库(虽然DEDE、DZ普通采用表前缀的方法来实现”一库多站”,但好的做法还是”一库一站”) 3. 按照user->db->tables_priv->columns_pri的顺序进行细粒度的权限控制 4. 为每个用户单独配置一个专属数据库,保证当前用户的所有操作只能发生在它自己的数据库中,防止SQL注入发生后,黑客通过注入点访问到系统表 账户权限安全配置需要的常用命令
1. 新建一个用户并给予相应数据库的权限
grant select,insert,update,delete,create,drop privileges on database.* to user@localhost identified by ‘passwd’; grant all privileges on database.* to user@localhost identified by ‘passwd’;
2. 刷新权限
3. 显示授权
4. 移除授权
5. 删除用户
6. 给用户改名
7. 给用户改密码
3. Mysql数据的网络安全配置
1. 主机层:
1) windows可以通过windows防火墙 2) Linux下可以通过iptables 来限制允许访问mysql端口的IP地址 //只允许指定的IP进行访问 iptables -A INPUT -p tcp -s xxxx.xxxx.xxxx.xxxx/24 –dport 3306 -j ACCEPT iptables -A INPUT -p tcp -s xxxx.xxxx.xxxx.xxxx/24 –dport 3306 -j ACCEPT .. iptables -P INPUT DROP 可以看到,这种方法的缺点是硬编码导致灵活性低,如果mysql的默认端口3306被修改了(例如8890),则这条iptables规则也需要相应的修改
这几行记录表明了root这个账户只能是本机登录,在部署的过程中,我们可以为指定账户添加某个安全的跳板机,并保证这个跳板机IP是不变的。
port = 3306
对mysql端口的修改可以从一定程度上防止端口扫描工具的扫描。
#vi /etc/my.cnf
[mysqld] max_user_connections 2
4. 密码策略安全
1. 从日志中获得典型SQL注入语句
2. 利用正则模型从日志中捕获注入攻击的发生 3. 在脱库、数据泄漏之后获得关于受攻击数据库的情况、泄漏范围等数据 mysql有以下几种日志,它们都在my.ini中进行配置:
1. 错误日志:-log-err
log-error=E:/wamp/logs/mysql_error.log
2. 查询日志(记录所有SQL语句):-log
3. 慢查询日志:-log-slow-queries 4. 更新日志:-log-update 5. 二进制日志:-log-bin//记录除select语句之外的所有sql语句到日志中,可以用来恢复数据文件log-bin=E:/wamp/logs/bin 查看日志开启情况:
6. Mysql数据库服务所在主机安全配置
1. 在windows下禁止使用local system(nt authority\system)来运行mysql账户,可以考虑使用network service或者自己新建一个windows账号,但是必须给与mysql程序所在目录的读取权限和data目录的读取和写入权限
2. 在linux下,新建一个mysql账号,并在安装的时候就指定mysql以mysql账户来运行,给与程序所在目录的读取权限,data所在目录的读取和写入权限。
0×2: mysql运行账号的磁盘权限
1. mysql运行账号需要给予程序所在目录的读取权限,以及data目录的读取和写入权限,保证mysql的正常运行
2. 不容许给予其他目录的写入和执行权限,特别是有网站的,这可以有效防御针对mysql的提权、或者webshell提权
3. 取消mysql运行账户对于cmd,sh等一些程序的执行权限,这可以防御当mysql核心帐号被黑客获取后进一步提权
0×3: Chrooting
1. ~/.bash_history
2. ~/.mysql_history .. cat /dev/null > ~/.bash_history cat /dev/null > ~/.mysql_history
0×5: mysql.sock安全配置
执行成功,result:
array(2) { [0]=> string(16) “apache@localhost” [“user()”]=> string(16) “apache@localhost” }
这意味着黑客在获取了目标服务器的webshell之后,可以在不知道mysql帐号密码的情况下直接从数据库中获取隐私数据。
1. 安华金和数据库防火墙系统(Xsecure-DBFirewall)
2. Snort入侵检测系统 能针对指定端口进行正则特征匹配方式的SQL注入检测 3. Java/J2EE 过滤器 对于J2ee的WEB应用来说,可以在HTTP请求上部署过滤器,并将SQL注入检测规律写在过滤器中 4. druid-sql-wall开源SQL检测、阻断系统 8. mysqld安全相关启动选项
1. –local-infile[={0|1}]
如果用–local-infile=0启动服务器,则客户端不能使用LOCAL in LOAD DATA语句,防止基于注入的直接文件读取数据泄漏
2. –old-passwords
3. (OBSOLETE) –safe-show-database
4. –safe-user-create
5. –secure-auth
6. –skip-grant-tables
7. –skip-name-resolve
8. –skip-networking
9. –skip-show-database
9. mysql备份策略
1. 本地备份
使用mysqldump进行备份非常简单,在备份数据库的时候,我们还可以同时使用管道gzip命令对备份文件进行压缩,可以采用Rsync的异地备份方式方式,将备份服务器的目录挂载到数据库服务器,将数据库文件备份打包后,通过crontab定时备份数据: 备份数据使用命令: #!/bin/sh time=`date +”(“%F”)”%R` $/usr/local/mysql/bin/mysqldump -u root -p111 database_backup | gzip > /home/zhenghan/mysql/mysql_backup.$time.gz # crontab -l # m h dom mon dow command00 00 * * * /home/zhenghan/mysql/backup.sh 恢复数据使用命令: gzip -d mysql_backup.\(2014-06-17\)00\:00.gz mysql_backup.(2014-06-17)00:00#mysql –u root -p111 < /home/zhenghan/mysql/mysql_backup.\(2014-06-17\)00\:00 2. 网络备份
3. MySQL本身自带的mysqldump备份
4. 直接复制数据库文件的备份形式
相关学习资料
from:http://www.2cto.com/Article/201406/310418.html (责任编辑:IT) |