本篇文章主要说一说MySQL数据库安全审计控制点的相关内容和理解。
MySQL除了自身带有的审计功能外,还存在着一些其它的审计插件。
虽然遇到这些插件的概率不高,我还是把这些插件的基本参数都列出来,到时候如果真遇到了,也不至于一头雾水。
a)应启用安全审计功能,审计覆盖到每个用户,对重要的用户行为和重要安全事件进行审计;
b)审计记录应包括事件的日期和时间、用户、事件类型、事件是否成功及其他与审计相关的信息;
c)应对审计记录进行保护,定期备份,避免受到未预期的删除、修改或覆盖等;
d)应对审计进程进行保护,防止未经授权的中断。
a)应启用安全审计功能,审计覆盖到每个用户,对重要的用户行为和重要安全事件进行审计;
在MySQL中自带了审计功能——general log,它会记录所有关于mysql的sql语句(所以会给服务器和数据库带来很大的资源占用)。
不过仅仅从测评要求的角度来说,如果开启了general log,那么是符合测评项a的。
查询的时候,可以使用log或者general关键词,这里用的是general(不过用log要好一些):
show global variables like '%general%'
图中的general_log变量的值为OFF,则表示没有开启。
general_log_file则表示日志存储在哪,图中是存储在一个文件中。
MySQL 5.1.6版开始,可以将日志存储在表当中,这个由log_output参数进行控制,值为file,则代表存储在文件中,为table,则代表存储在gengera_log表中。
mysql> show variables like 'log_output';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_output | TABLE |
+---------------+-------+
mysql> select * from general_log;
| 2018-07-17 23:00:12 | root[root] @ localhost [] | 2 | 1132333306 | Query | select * from test.student3
也可以去看一看/etc/my.cnf文件,查看是否启用了general_log:
[mysqld]
general_log = on // on为开启;off为关闭
general_log_file = /var/log/generalLog.log // 审计信息存储位置
log_timestamps = SYSTEM // 设置日志文件的输出时间为地方时
修改my.cnf文件和设置global变量的区别在于,设置global变量,则数据库重启后设置就失效了。
而修改my.cnf文件,数据库每次启动后,都会先去my.cnf读取变量的值,再传给相应的global变量。
下面其它变量也是如此。
另外要说的一点是,变量general_log的类型是bool,可以设置的值为OFF(或者0),以及ON(或者1),所以设置为ON和1是一个意思。
该插件可以用于MySQL的一些版本上,比如MySQL 5.7.18。
该插件的相关变量为:
SHOW GLOBAL VARIABLES LIKE 'server_audit%';
+-------------------------------+-----------------------+
| Variable_name | Value |
+-------------------------------+-----------------------+
| server_audit_events | CONNECT,QUERY,TABLE |
| server_audit_excl_users | |
| server_audit_file_path | server_audit.log |
| server_audit_file_rotate_now | OFF |
| server_audit_file_rotate_size | 1000000 |
| server_audit_file_rotations | 9 |
| server_audit_incl_users | |
| server_audit_logging | ON |
| server_audit_mode | 0 |
| server_audit_output_type | file |
| server_audit_query_log_limit | 1024 |
| server_audit_syslog_facility | LOG_USER |
| server_audit_syslog_ident | mysql-server_auditing |
| server_audit_syslog_info | |
| server_audit_syslog_priority | LOG_INFO |
+-------------------------------+-----------------------+
解释如下:
server_audit_output_type:指定日志输出类型,可为SYSLOG或FILE
server_audit_logging:启动或关闭审计
server_audit_events:指定记录事件的类型,可以用逗号分隔的多个值(connect,query,table),如果开启了查询缓存(query cache),查询直接从查询缓存返回数据,将没有table记录
server_audit_file_path:如server_audit_output_type为FILE,使用该变量设置存储日志的文件,可以指定目录,默认存放在数据目录的server_audit.log文件中
server_audit_file_rotate_size:限制日志文件的大小
server_audit_file_rotations:指定日志文件的数量,如果为0日志将从不轮转
server_audit_file_rotate_now:强制日志文件轮转
server_audit_incl_users:指定哪些用户的活动将记录,connect将不受此变量影响,该变量比server_audit_excl_users优先级高
server_audit_syslog_facility:默认为LOG_USER,指定facility
server_audit_syslog_ident:设置ident,作为每个syslog记录的一部分
server_audit_syslog_info:指定的info字符串将添加到syslog记录
server_audit_syslog_priority:定义记录日志的syslogd priority
server_audit_excl_users:该列表的用户行为将不记录,connect将不受该设置影响
server_audit_mode:标识版本,用于开发测试
这里我们比较关注的是server_audit_logging、server_audit_events、server_audit_output_type、server_audit_file_path、server_audit_file_rotate_size、server_audit_file_rotations、server_audit_file_rotate_now。
server_audit_logging:
即为是否开启,bool类型,值为ON(1)以及OFF(0)。
server_audit_events:
记录的事件,如果为空字符串,则代表记录所有的事件。
CONNECT:连接、断开连接和失败的连接,包括错误代码
QUERY:以纯文本形式执行的查询及其结果,包括由于语法或权限错误而失败的查询
TABLE:受查询执行影响的表
QUERY_DDL:与QUERY相同,但只筛选DDL类型的查询(create、alter、drop、rename和truncate语句,create/drop[procedure/function/user]和rename user除外(它们不是DDL)
QUERY_DML:与QUERY相同,但只筛选DML类型的查询(do、call、load data/xml、delete、insert、select、update、handler和replace语句)
QUERY_DCL:与QUERY相同,但只筛选DCL类型的查询(create user、drop user、rename user、grant、revoke和set password语句)
QUERY_DML_NO_SELECT:与QUERY_DML相同,但不记录SELECT查询。(从1.4.4版开始)(do、call、load data/xml、delete、insert、update、handler和replace语句)
server_audit_file_path:
当server_audit_output_type为file时,将路径和文件名设置为日志文件。如果指定的路径作为目录存在,那么将在该目录内创建名为“ server_audit.log”的日志。否则,该值将被视为文件名。默认值“ server_audit.log”,这意味着将在数据库目录中创建此文件。
server_audit_file_rotate_size、server_audit_file_rotations、server_audit_file_rotate_now:
当server_audit_output_type为file时,是否强制轮转(server_audit_file_rotate_now),每个日志文件的最大大小(server_audit_file_rotate_size),以及日志文件的最大数量(server_audit_file_rotations)。
更多变量的相关的解释可以查看官方文档: MariaDB Audit Plugin Options and System Variables
那么,从这个插件的功能来看,基本上默认配置就可以满足测评项的要求。
MySQL 企业版的 Enterprise Edition 中自带 Audit Plugin ,名为 audit_log.so。
对于该插件,可以在my.cnf文件中加入以下参数启用它:
[mysqld]
plugin-load=audit_log.so
也可以查询插件,看到插件的状态:
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM INFORMATION_SCHEMA.PLUGINS
WHERE PLUGIN_NAME LIKE 'audit%';
+-------------+---------------+
| PLUGIN_NAME | PLUGIN_STATUS |
+-------------+---------------+
| audit_log | ACTIVE |
+-------------+---------------+
该插件的相关系统变量为:
mysql> SHOW VARIABLES LIKE 'audit_log%';
+-----------------------------+--------------+
| Variable_name | Value |
+-----------------------------+--------------+
| audit_log_buffer_size | 1048576 |
| audit_log_connection_policy | ALL |
| audit_log_current_session | OFF |
| audit_log_exclude_accounts | |
| audit_log_file | audit.log |
| audit_log_filter_id | 0 |
| audit_log_flush | OFF |
| audit_log_format | NEW |
| audit_log_include_accounts | |
| audit_log_policy | ALL |
| audit_log_rotate_on_size | 0 |
| audit_log_statement_policy | ALL |
| audit_log_strategy | ASYNCHRONOUS |
+-----------------------------+--------------+
audit_log_connection_policy:
audit_log_exclude_accounts:
不应记录事件的帐户,除此之外的账户的事件都会被记录。该值应为NULL或包含一个或多个用逗号分隔的帐户名列表的字符串。
audit_log_file:
日志记录的文件名,可以是相对路径(相对于数据库目录)和完整路径。
audit_log_format:
日志格式,可以是 OLD(旧样式XML), NEW(新样式XML,默认值)和(从MySQL 5.7.21开始)JSON。
audit_log_include_accounts:
要包括在审核日志记录中的帐户。如果设置了此变量,则仅审核这些帐户。
注意,audit_log_exclude_accounts与audit_log_include_accounts是互斥的,它们之间只有一个的值为非null,不能同时为非null。
audit_log_policy:
audit_log_rotate_on_size:
如果 audit_log_rotate_on_size 值为0,则审核日志插件不会执行自动日志文件轮换。而是手动使用audit_log_flush刷新日志文件。在这种情况下,请在刷新文件之前在服务器外部手动重命名该文件(要不然原来的记录就没了)。
如果该 audit_log_rotate_on_size 值大于0,则会自动进行基于大小的日志文件轮换。每当写入日志文件导致其大小超过该 audit_log_rotate_on_size 值时,审核日志插件都会关闭当前日志文件,将其重命名,然后打开一个新的日志文件。
如果将此变量设置为不是4096的倍数的值,它将被截断为最接近的倍数。(因此,将其设置为小于4096的效果是将其设置为0且不进行旋转,除非手动进行。)
audit_log_statement_policy:
应该被记录的语句事件,在服务器启动的时候如果audit_log_statement_policy和audit_log_policy都显示赋予了值,那么audit_log_statement_policy可能会被audit_log_policy覆盖。
更多详细的解释请看官方文档: MySQL Enterprise Audit
基本上默认配置也足够满足测评项要求了。
也是一个审核插件,其相关参数如下:
SHOW GLOBAL VARIABLES LIKE '%audi%';
audit_json_file #是否开启audit功能(ON\OFF)
audit_json_log_file #log日志名称及存储位置,默认mysql的data目录
audit_record_cmds='' #设置需要监控的SQL命令,默认全部(即该值为null)
audit_record_cmds='insert,delete,update,create,drop,alter,grant,truncate' #这是一些例子
audit_record_objs='' #设置需要监控的数据库名称和表名,默认全部(即该值为null)
audit_record_objs=‘mysql.*’ #一个例子
audit_whitelist_users #用户白名单
更多详细解释请查看官方文档: McAfee的audit
基本上启用后就满足测评项要求了。
b)审计记录应包括事件的日期和时间、用户、事件类型、事件是否成功及其他与审计相关的信息;
只要启用了审计功能,无论是自带的审计还是插件,在记录的信息上都能满足这个要求。
其记录内容如下:
mysql> select * from general_log;
| 2018-07-17 23:00:12 | root[root] @ localhost [] | 2 | 1132333306 | Query | select * from test.student3
日志的格式解释可看官方文档: MariaDB Audit Plugin – Log Format
该插件的日志文件可以是XML或者JSON格式,以XML为例:
2019-10-03T14:09:38 UTC
6_2019-10-03T14:06:33
Query
5
0
0
root[root] @ localhost [127.0.0.1]
localhost
127.0.0.1
drop_table
DROP TABLE IF EXISTS t
相似的格式介绍请查看官方文档: 审核日志文件格式
该插件日志文件的格式是json:
{
"msg-type": "activity",
"date": "1510038432019",
"thread-id": "43",
"query-id": "1891",
"user": "root",
"priv_user": "root",
"ip": "",
"host": "localhost",
"connect_attrs": {
"_os": "linux-glibc2.5",
"_client_name": "libmysql",
"_pid": "4009",
"_client_version": "5.7.9",
"_platform": "x86_64",
"program_name": "mysql"
},
"pid": "4009",
"os_user": "root",
"appname": "mysql",
"rows": "1",
"cmd": "insert",
"objects": [
{
"db": "part",
"name": "e",
"obj_type": "TABLE"
}
],
"query": "insert into e values (9898,'smart','james')"
}
详细的格式介绍请查看官方文档: mysql-audit
c)应对审计记录进行保护,定期备份,避免受到未预期的删除、修改或覆盖等;
对审计记录进行保护,那么这里就不细说了,说一下大概的原则。
无论是自带的审计还是审计插件,如果审核记录存储于文件中的,应该在操作系统上对这些日志文件的权限进行限定,仅允许数据库管理员可对这些文件进行访问、修改等。同时也要限制MySQL中的file_priv权限。
如果审核记录存储于数据库表中,那么也应该对数据库的表进行权限设置,仅数据库管理员可对审核记录表进行访问、修改等。
定期备份就不用多做什么说明了,检查备份文件和备份策略即可。
在这里有一个地方想探讨下,在等级保护2.0试行稿中,对日志的留存时间有要求:
这里的法律法规要求一般来说指的就是《网络安全法》,其中有关日志留存时间的条款如下:
(三)采取监测、记录网络运行状态、网络安全事件的技术措施,并按照规定留存相关的网络日志不少于六个月;
在等保正式2.0正式稿中,这个测评项被删除了,那么《网络安全法》对于日志留存时间(6个月)的要求是否落在了测评项c当中呢?
从基本要求来看,应该不是,其中没有这个要求:
当然,既然网络安全法这么规定了,等级保护肯定还是有测评项来实现该要求的,就是在安全管理中心的集中管控的测评项中:
按照我的个人理解,6个月的留存时间要求,应该是在集中管控的c测评项中去落实。
怎么测评呢?首先肯定要有相关的审计设备,也就是数据库审计以及综合日志审计设备,没有这些设备,集中管控d测评项的第一个要求就没法满足。
然后在这些设备中,查看汇总的审计记录留存时间是否满足了法律法规的要求。
也就是,不需要跑去单个的设备上,查看每个设备的审计记录是否满足法律法规的要求。
否则,等级保护2.0正式稿中就不会将应确保审计记录的留存时间符合法律法规要求挪到集中管控里面去了。
为什么说到这个呢?因为我在初级教程里看到了关于留存时间的要求:
综上所述,我个人觉得关于日志留存时间6个月的要求,应该再集中管控的d测评项中进行统一描述,而不是在每个测评对象的安全审计的c测评项中进行描述。
d)应对审计进程进行保护,防止未经授权的中断。
这个就比较简单了,有两个地方可以对审计进程进行配置。
一个是my.cnf,这里就需要操作系统上对配置文件的权限进行限制,只允许数据库管理有权限进行修改。(同时也要限制MySQL中的file_priv权限。)
另外一个就是那些变量了,似乎是需要super权限才可以设置全局变量,那么这里的话就需要查看super权限给了哪些账户。
*本文原创作者:起于凡而非于凡,本文属于FreeBuf原创奖励计划,未经许可禁止转载