mita2 database life

主にMySQLに関するメモです

MySQL ヒストリーに記録されない条件

TL; DR;

  • *IDENTIFIED*:*PASSWORD* にマッチしたクエリ、つまりパスワードを含むクエリはヒストリーに記録されない
  • 環境変数 MYSQL_HISTIGNORE で記録しないクエリを追加指定できる

ヒストリーに記録されない時がある

mysql コマンド には履歴機能があります。 Linuxのシェルのように、過去に実行したSQLを上の矢印キーで遡ったり、Ctrl-R でキーワード検索することが出来ます。

時々、ヒストリーに記録されないSQLがあることが気になっていました。 今回はその条件を調べてみました。

ソースから辿ってみる

client/mysql.cc を読んでいきます。 add_filtered_history() という関数でヒストリーファイルに追記しています。 ignore_matcher がヒストリーに残さないものを判定していそうです。

2929 /* Add the given line to mysql history and syslog. */
2930 static void add_filtered_history(const char *string) {
2931   // line shouldn't be on history ignore list
2932   if (ignore_matcher.is_matching(string, charset_info)) return;
2933
2934 #ifdef HAVE_READLINE
2935   if (!quick && not_in_history(string)) add_history(string);
2936 #endif
2937
2938   if (opt_syslog) add_syslog(string);
2939 }

ignore_matcher は 以下の箇所で定義されており、HI_DEFAULTS がデフォルト値です。 そして、 MYSQL_HISTIGNORE という環境変数でヒストリーに記録しないパターンを追加できることもわかりました。

1349   if (!status.batch) {
1350     // history ignore patterns are initialized to default values
1351     ignore_matcher.add_patterns(HI_DEFAULTS);
1352
1353     /*
1354       Additional patterns may be supplied using either --histignore option or
1355       MYSQL_HISTIGNORE environment variable. If supplied, they'll get appended
1356       to the default patterns. In case both are specified, pattern(s) supplied
1357       using --histignore option will be used.
1358     */
1359     if (opt_histignore)
1360       ignore_matcher.add_patterns(opt_histignore);
1361     else if (getenv("MYSQL_HISTIGNORE"))
1362       ignore_matcher.add_patterns(getenv("MYSQL_HISTIGNORE"));

HI_DEFAULTS は以下のように定義されていました。 パスワードが入っているSQLをヒストリーに記録してしまうと、ヒストリーファイルからパスワードが読み取られてしまうリスクがあるため、記録しないということでしょう。

132 /** default set of patterns used for history exclusion filter */
133 const static std::string HI_DEFAULTS("*IDENTIFIED*:*PASSWORD*");

MYSQL_HISTIGNORE を試してみる

環境変数 MYSQL_HISTIGNORE で無視する条件を追加してみます。 HIMITSU を含んだSQLをヒストリーに記録しないようにします。

$ export MYSQL_HISTIGNORE='*HIMITSU*'

$ mysql
mysql> SELECT 'HOGEHOGE';
+----------+
| HOGEHOGE |
+----------+
| HOGEHOGE |
+----------+
1 row in set (0.00 sec)

mysql> SELECT 'HIMITSU NO HOGEHOGE';
+---------------------+
| HIMITSU NO HOGEHOGE |
+---------------------+
| HIMITSU NO HOGEHOGE |
+---------------------+
1 row in set (0.00 sec)

ちゃんと、HIMITSU NO HOGEHOGE が無視されて、HOGEHOGEだけがヒストリーファイルに記録されてました。

$ cat ~/.mysql_history
_HiStOrY_V2_
SELECT\040'HOGEHOGE';
exit

マニュアルにも書いてある

ソースから辿りましたが、マニュアルにもちゃんと記載がありました。

mysql ignores for logging purposes statements that match any pattern in the “ignore” list. By default, the pattern list is "IDENTIFIED:PASSWORD", to ignore statements that refer to passwords. Pattern matching is not case-sensitive. Within patterns, two characters are special: https://dev.mysql.com/doc/refman/8.0/en/mysql-logging.html