MySQL Audit Plugin

18 篇文章 0 订阅

MySQL Audit Plugin

一、Audit plugin用于对Mysql连接和操作进行审计,分别对应以下两个事件见(/usr/include/mysql/plugin_audit.h)

1. MYSQL_AUDIT_CONNECTION_CLASS

连接事件又细分为:

MYSQL_AUDIT_CONNECTION_CONNECT 0

MYSQL_AUDIT_CONNECTION_DISCONNECT 1

MYSQL_AUDIT_CONNECTION_CHANGE_USER 2

2. MYSQL_AUDIT_GENERAL_CLASS

操作事件细分为:

MYSQL_AUDIT_GENERAL_LOG 0

MYSQL_AUDIT_GENERAL_ERROR 1

MYSQL_AUDIT_GENERAL_RESULT 2

MYSQL_AUDIT_GENERAL_STATUS 3

二、插件代码主要包括三个函数

init 加载插件

deinit 卸载插件

notify 实际执行具体功能函数

声明插件的宏

mysql_declare_plugin

mysql_declare_plugin_end;

Mysql5.5.12版本与5.5.16/17 notify 参数不同,因plugin_audit.h中相应结构体有差异。

1. 5.5.12

plugin_audit.h

struct mysql_event // 仅函数一个成员event_class识别连接与操作事件

struct mysql_event_general // 包含成员event_class

struct mysql_event_connection // 包含成员 event_class

void (*event_notify)(MYSQL_THD, const struct mysql_event *); // 为notify函数原型

2. 5.5.16/17

plugin_audit.h

struct mysql_event_general

struct mysql_event_connection

void (*event_notify)(MYSQL_THD, unsigned int, const void *); // 第二个参数为识别连接与操作事件,第三个参数为event结构

三、 记录事件到/tmp/my_general_log.log文件

#include <stdio.h>

#include <mysql/plugin_audit.h>

#if !defined(__attribute__) && (defined(__cplusplus) || !defined(__GNUC__) || __GNUC__ == 2 && __GNUC_MINOR__ < 8)

#define __attribute__(A)

#endif

static FILE *log_fp;

static volatile int localhost_commands;

// 加载插件

static int my_general_log_plugin_init(void *arg __attribute__((unused)))

{

log_fp = NULL;

localhost_commands = 0;

return 0;

}

// 卸载插件

static int my_general_log_plugin_deinit(void *arg __attribute__((unused)))

{

fclose(log_fp);

return 0;

}

//5.5.12

//static void my_general_log_notify(MYSQL_THD thd, const struct mysql_event_general *event)

static void my_general_log_notify(MYSQL_THD thd,unsigned int type, const void* event)

{

mysql_event_general *pEvent;

if (log_fp == NULL)

log_fp = fopen("/tmp/my_general_log.log","a");

// 5.5.12

// if (event->event_class == MYSQL_AUDIT_GENERAL_CLASS && log_fp != NULL)

if (type == MYSQL_AUDIT_GENERAL_CLASS && log_fp != NULL)

{

localhost_commands++;

pEvent = (mysql_event_general *)event;

if (pEvent->general_query != NULL && *(pEvent->general_query) != ' ')

{

fprintf(log_fp, "%s;\n\n", pEvent->general_query);

fflush(log_fp);

}

}

// 5.5.12

// event->event_class == MYSQL_AUDIT_CONNECTION_CLASS && log_fp != NULL)

else if (type == MYSQL_AUDIT_CONNECTION_CLASS && log_fp != NULL)

{

localhost_commands++;

const struct mysql_event_connection *cpEvent =

(const struct mysql_event_connection *)event;

switch (cpEvent->event_subclass)

{

case MYSQL_AUDIT_CONNECTION_CONNECT:

fprintf(log_fp,"################connect#################\n");

fprintf(log_fp,"status:%d\nthread_id:%d\nuser:%s\nhost:%s\nip:%s\ndatabase:%s\n",

cpEvent->status,cpEvent->thread_id,cpEvent->user,cpEvent->host,

cpEvent->ip,cpEvent->database);

fflush(log_fp);

break;

case MYSQL_AUDIT_CONNECTION_DISCONNECT:

break;

case MYSQL_AUDIT_CONNECTION_CHANGE_USER:

break;

default:

break;

}

}

}

static struct st_mysql_audit my_general_log_descriptor =

{

MYSQL_AUDIT_INTERFACE_VERSION, // 插件类型:审计

NULL,

my_general_log_notify, // 功能函数函数指针

{(unsigned long) -1} // -1 不过滤事件

// MYSQL_AUDIT_CONNECTION_CLASSMASK:仅审计连接事件

// MYSQL_AUDIT_GENERAL_CLASSMASK:仅审计操作事件

};

// 状态值在Mysql中通过 show status like ‘my_general_log_commands’;查看

static struct st_mysql_show_var my_general_log_status[] =

{

{"my_general_log_commands", (char *)&localhost_commands, (enum_mysql_show_type) SHOW_INT},

{0, 0, (enum_mysql_show_type)0}

};

// 声明插件为宏成对出现

//mysql_declare_plugin(my_general_log)

/*********************/

// mysql_declare_plugin_end;

mysql_declare_plugin(my_general_log)

{

MYSQL_AUDIT_PLUGIN,

&my_general_log_descriptor,

"my_general_log", // 插件名 * install plugin 这的插件名,故一个库中// 可以写多个插件

"YUHUI ZHENG",

"A general log that will log localhost access only",

PLUGIN_LICENSE_GPL,

my_general_log_plugin_init, // 加载函数 * 不能写错,否则安装插件会失败

my_general_log_plugin_deinit, // 卸载函数 * 不能写错,否则安装插件会失败

0x0001,

my_general_log_status,

NULL,

NULL

}

mysql_declare_plugin_end;

Makefile 文件:

MYSQL_INST=/usr/lib64/mysql/plugin

CFLAGS=-D_HAVE_CONFIG_H -DMYSQL_DYNAMIC_PLUGIN -fPIC

all:my_general_log.so

my_general_log.o:my_general_log.c

g++ $(CFLAGS) -I/usr/include/mysql -c my_general_log.c

my_general_log.so:my_general_log.o

g++ -shared my_general_log.o -o my_general_log.so

install:my_general_log.so

cp my_general_log.so $(MYSQL_INST)/my_general_log.so

clean:

rm -rf my_general_log.so my_general_log.o

四、安装、卸载插件

make

make install

在MYSQL中执行

install plugin 插件名 soname’库名’

eg:install plugin my_general_log soname’my_general_log.so’;

卸载插件:

uninstall plugin 插件名;

在tmp/my_general_log.log中记录事件

五、参考文献

n http://docs.huihoo.com/mysql/refman-5.5-en/extending-mysql.html#audit-plugins

n http://blog.csdn.net/zhaiwx1987/article/details/6594609

n http://www.taobaodba.com/html/633_audit-plugin-%e5%9c%a8%e6%b7%98%e5%ae%9d%e7%9a%84%e5%ba%94%e7%94%a8.html



********************************************************************************************

MySQL数据库Audit插件的使用技巧总结

MySQL数据库中(5.5版本),增加了一个新的插件:Audit plugin,用于对数据库连接和数据库操作进行审计。接下来我们详细介绍Audit插件的使用。

相关代码如下:

  
  
  1. sql/sql_audit.cc

该文件定义了audit插件的接口函数。

  
  
  1. sql/sql_audit.h

申明函数,并定义了函数mysql_audit_general_log,在触发audit时,首先调用的就是该函数。

  
  
  1. plugin/audit_null/audit_null.c

这是一个模板程序,给出了一个最基本的audit插件所需要定义的接口。

为了实现一个完整的audit程序,需要包括插件初始化、主要函数、卸载插件后的调用函数。这里我们以audit_null.c为例:

  
  
  1. static int audit_null_plugin_init(void *arg __attribute__((unused)))

在安装插件时,会调用该函数,主要用于做一些初始化的工作,比如初始化全局变量等。

  
  
  1. static void audit_null_notify(MYSQL_THD thd, unsigned int event_class, constvoid *event)

这是audit插件的主要函数,在相应的事件被触发时,将会调用到该函数,参数包括:

thd:触发该函数的线程,在结构体THD中包含了相当丰富的信息,可以借此实现很多有趣的功能

event_class/event:前者表示事件的类型,用于决定第三个参数event结构体的类型,使用宏定义,值为MYSQL_AUDIT_GENERAL_CLASS时表示由操作数据库的行为所触发,值为MYSQL_AUDIT_CONNECTION_CLASS时表示由发起数据库连接所触发,而针对不同的类型,也会调用不同的接口函数来触发audit。

  
  
  1. staticaudit_handler_t audit_handlers[] =
  2. {
  3. general_class_handler,connection_class_handler
  4. };

对上述两种情况下,又会细分到多个事件类型,在文件plugin_audit.h中进行了定义

1. 发起连接时

  
  
  1. #defineMYSQL_AUDIT_CONNECTION_CONNECT 0

完成认证后触发

  
  
  1. #define MYSQL_AUDIT_CONNECTION_DISCONNECT 1

连接被中断时触发

  
  
  1. #define MYSQL_AUDIT_CONNECTION_CHANGE_USER 2

在执行COM_CHANGE_USER命令后触发。

event参数的结构为:mysql_event_connection。

2.操作数据库时

  
  
  1. #defineMYSQL_AUDIT_GENERAL_LOG 0

在提交给general query log之前被触发

  
  
  1. #define MYSQL_AUDIT_GENERAL_ERROR 1

在发送给用户错误之前触发

  
  
  1. #define MYSQL_AUDIT_GENERAL_RESULT 2

当将结果集合发送给用户后触发

  
  
  1. #defineMYSQL_AUDIT_GENERAL_STATUS 3

当发送一个结果集或发生错误时被触发。event参数的结构体为:mysql_event_general。

不管event的结构体是哪一个,都在其中记录了上述七种事件类型,我们就可以根据不同的事件类型,有针对性的进行插件代码的编写。

3. static int audit_null_plugin_deinit(void*arg __attribute__((unused)))

当卸载插件时,会调用该函数,可以用来执行一些释放资源、关闭文件等操作

4. 定义插件的描述符结构体:

  
  
  1. struct st_mysql_audit
  2. {
  3. int interface_version;
  4. void (*release_thd)(MYSQL_THD);
  5. void (*event_notify)(MYSQL_THD, unsigned int, const void *);
  6. unsigned long class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
  7. };

Version,值一般为MYSQL_AUDIT_INTERFACE_VERSION。

release_thd,一般设置为NULL。

event_notify,主要的处理函数,当发生某些事件时被调用(audit_null_notify)。

class_mask,掩码。

release_thd和event_notify可以结合起来用,当事件触发event_notify时,这时候插件是不可以uninstall的,当完成调用后,服务器会通知release_thd函数。这样,我们可以在event_notify中分配资源,并在release_thd中统一的进行释放。

5.定义statues变量,用于指定在调用SHOWSTATIS时,显示哪些值

  
  
  1. static struct st_mysql_show_var audit_null_status[]

6. 插件的库描述符

  
  
  1. mysql_declare_plugin(audit_null)
  2. {
  3. MYSQL_AUDIT_PLUGIN, /* type */
  4. &audit_null_descriptor, /* descriptor */
  5. "NULL_AUDIT", /* name */
  6. "Oracle Corp", /* author */
  7. "Simple NULL Audit", /* description */
  8. PLUGIN_LICENSE_GPL,
  9. audit_null_plugin_init, /* init function (when loaded) */
  10. audit_null_plugin_deinit, /* deinit function (when unloaded) */

其中 第三个字段 “NULL_AUDIT”就是在执行INSTALLPLUGIN时的插件名,如果不一致,不报无法找到在库文件中找到符号的错误。

总结:

Audit插件可以被多种事件所触发,因此,当服务器繁忙时,需要小心谨慎的编写代码,防止产生太多的额外开销,以影响服务器的整体性能。



利用mysql的audit审计功能记录用户操作信息

mysql的audit审计功能可以来记录用户操作信息。该审计功能是被自动触发的,通过结构体来实现,根据不同的触发条件触发相应的事件。本文介绍了这一过程,希望能对读者有所帮助。

AD:51CTO学院:IT精品课程在线看!

mysql数据库中我们如果想记录用户的操作信息,可以通过audit审计功能来来实现。该功能是被自动触发的,在文件plugin_audit.h中可以看到比较详细的定义。在audit插件中,可控制的变量包括THD以及事件。

其中事件分为两种结构体,可以进行强制转换:

第一种:

    
    
  1. struct mysql_event_general   
  2.  
  3. {  
  4.  
  5. unsigned int event_subclass;   
  6.  
  7. int general_error_code;   
  8.  
  9. unsigned long general_thread_id;   
  10.  
  11. const char *general_user;   
  12.  
  13. unsigned int general_user_length;   
  14.  
  15. const char *general_command;   
  16.  
  17. unsigned int general_command_length;   
  18.  
  19. const char *general_query;   
  20.  
  21. unsigned int general_query_length;   
  22.  
  23. struct charset_info_st *general_charset;   
  24.  
  25. unsigned long long general_time;   
  26.  
  27. unsigned long long general_rows;   
  28.  
  29. }; 

触发条件:

#define MYSQL_AUDIT_GENERAL_LOG 0 :在提交给general query log之前被触发。

#define MYSQL_AUDIT_GENERAL_ERROR 1 :在发送给用户错误之前触发。

#define MYSQL_AUDIT_GENERAL_RESULT 2 : 当将结果集合发送给用户后触发。

#define MYSQL_AUDIT_GENERAL_STATUS 3  :  当发送一个结果集或发生错误时被触发。

第二种:

    
    
  1. struct mysql_event_connection   
  2.  
  3. {  
  4.  
  5. unsigned int event_subclass;   
  6.  
  7. int status;   
  8.  
  9. unsigned long thread_id;   
  10.  
  11. const char *user;   
  12.  
  13. unsigned int user_length;   
  14.  
  15. const char *priv_user;   
  16.  
  17. unsigned int priv_user_length;   
  18.  
  19. const char *external_user;   
  20.  
  21. unsigned int external_user_length;   
  22.  
  23. const char *proxy_user;   
  24.  
  25. unsigned int proxy_user_length;   
  26.  
  27. const char *host;   
  28.  
  29. unsigned int host_length;   
  30.  
  31. const char *ip;   
  32.  
  33. unsigned int ip_length;   
  34.  
  35. const char *database;   
  36.  
  37. unsigned int database_length;   
  38.  
  39. }; 

触发条件:

#define MYSQL_AUDIT_CONNECTION_CONNECT 0 :  完成认证后触发。

#define MYSQL_AUDIT_CONNECTION_DISCONNECT 1 : 连接被中断时触发。

#define MYSQL_AUDIT_CONNECTION_CHANGE_USER 2 : 在执行COM_CHANGE_USER命令后触发。

从上面的分析,我们可以看出,在event中存储了相当丰富的信息,将notify函数进行了如下简单的修改:

    
    
  1. static void audit_null_notify(MYSQL_THD thd __attribute__((unused)),   
  2.  
  3. unsigned int event_class,  
  4.  
  5. const void *event)  
  6.  
  7. {   
  8.  
  9. const struct mysql_event_general *pEvent;  
  10.  
  11. if (log_fp == NULL)  
  12.  
  13. log_fp = fopen("/tmp/rec.log", "a");  
  14.  
  15. number_of_calls++;  
  16.  
  17. if (event_class == MYSQL_AUDIT_GENERAL_CLASS && log_fp != NULL){  
  18.  
  19. pEvent = (const struct mysql_event_general *) event;  
  20.  
  21. if ( pEvent->event_subclass == MYSQL_AUDIT_GENERAL_RESULT &&  
  22.  
  23. pEvent->general_query != NULL  
  24.  
  25. && *(pEvent->general_query) != '\0') {   
  26.  
  27. // fprintf(log_fp, "user:%s,host:%s,command:%s\n",&thd->security_ctx->priv_user[0],   
  28.  
  29. // (char *) thd->security_ctx->host_or_ip ,  
  30.  
  31. // pEvent->general_query);  
  32.  
  33. time_t cur = time(NULL);  
  34.  
  35. fprintf(log_fp, "%s %s\n%s\n", ctime(&cur) , pEvent->general_user , pEvent->general_query);  
  36.  
  37. fflush(log_fp);  
  38.  
  39. }  
  40.  
  41. }  
  42.  

这样,我们实现了记录用户名、用户主机信息以及sql操作等相关信息。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值