Easiest Application-Level MySQL Auditing

This article shows the easiest way to audit commands to a MySQL database, assuming all content happens from an application. Now, this will use a lot of storage, and doubles the query load for each query, but it’s useful for when you know you want to capture the information of someone using the application.

The basic premise is simple. Logon to your nearest MySQL server and type the following:

SELECT CURRENT_USER(), USER();

Chances are the values are different. More on this later.

First, create a table:

CREATE TABLE `action` (
`user` varchar(77) NOT NULL default '',
`asuser` varchar(77) NOT NULL default '',
`db` varchar(64) NOT NULL default '',
`query` mediumtext NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Why varchar(77)? Because the mysql.user table puts a maximum of 16 characters for the username, and 60 characters for the hostname. And then there’s the 1 character “@”. Similarly, database names are limited to varchar(64).

The “asuser” column is the grant record that the user is acting as. For instance, a connection with the username “sheeri” from the host “www.sheeri.com” has a user value of “sheeri@www.sheeri.com” but may have an asuser value of “sheeri@’%.sheeri.com'” — whatever the GRANT statement that applies to my current user is. This is the difference between CURRENT_USER() and USER().

Then, create the function — here’s a PHP example:
function my_mysql_query ($query, $dblink) {
$action="INSERT INTO action (user,asuser,db,query) VALUES (CURRENT_USER(), USER(), DATABASE(), $query)";
mysql_query($action, $dblink);
mysql_query($query, $dblink);
}

Of course, we could also add in application specific information. For a web-based application where there is an overall password instead of a different password for each customer or user, this does not help. However in that case, a session username and client IP can be easily gotten from environment variables and used instead of the MySQL-specific “user@host”.

To use it, simply use my_mysql_query in place of mysql_query.

Note that this is the quick-and-dirty way to do it.

This article shows the easiest way to audit commands to a MySQL database, assuming all content happens from an application. Now, this will use a lot of storage, and doubles the query load for each query, but it’s useful for when you know you want to capture the information of someone using the application.

The basic premise is simple. Logon to your nearest MySQL server and type the following:

SELECT CURRENT_USER(), USER();

Chances are the values are different. More on this later.

First, create a table:

CREATE TABLE `action` (
`user` varchar(77) NOT NULL default '',
`asuser` varchar(77) NOT NULL default '',
`db` varchar(64) NOT NULL default '',
`query` mediumtext NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Why varchar(77)? Because the mysql.user table puts a maximum of 16 characters for the username, and 60 characters for the hostname. And then there’s the 1 character “@”. Similarly, database names are limited to varchar(64).

The “asuser” column is the grant record that the user is acting as. For instance, a connection with the username “sheeri” from the host “www.sheeri.com” has a user value of “sheeri@www.sheeri.com” but may have an asuser value of “sheeri@’%.sheeri.com'” — whatever the GRANT statement that applies to my current user is. This is the difference between CURRENT_USER() and USER().

Then, create the function — here’s a PHP example:
function my_mysql_query ($query, $dblink) {
$action="INSERT INTO action (user,asuser,db,query) VALUES (CURRENT_USER(), USER(), DATABASE(), $query)";
mysql_query($action, $dblink);
mysql_query($query, $dblink);
}

Of course, we could also add in application specific information. For a web-based application where there is an overall password instead of a different password for each customer or user, this does not help. However in that case, a session username and client IP can be easily gotten from environment variables and used instead of the MySQL-specific “user@host”.

To use it, simply use my_mysql_query in place of mysql_query.

Note that this is the quick-and-dirty way to do it.