MySQL 8.0 リファレンスマニュアル


MySQL 8.0 リファレンスマニュアル  /  ...  /  SQL ベースのアカウントアクティビティ監査

6.2.22 SQL ベースのアカウントアクティビティ監査

アプリケーションは次のガイドラインを使用することで、データベースアクティビティーを MySQL アカウントに関連付ける SQL ベースの監査を実行できます。

MySQL アカウントは、mysql.user システムテーブルの行に対応します。 クライアントが正常に接続すると、サーバーはこのテーブル内の特定の行にアクセスするクライアントを認証します。 この行の User および Host カラムの値は、アカウントを一意に識別し、アカウント名が SQL ステートメントに書き込まれる 'user_name'@'host_name' 形式に対応します。

クライアントを認証する際に使用されるアカウントによって、クライアントが持っている権限が特定されます。 通常、CURRENT_USER() 関数を呼び出すと、このアカウントがどのクライアントユーザー用であるかを特定できます。 その値は、アカウントの user テーブル行の User および Host カラムで構成されています。

ただし、CURRENT_USER() 値がクライアントユーザーではなく、別のアカウントに対応するという状況もあります。 これは、権限チェックがクライアントのアカウントに基づいて実行されないコンテキストで発生します。

  • SQL SECURITY DEFINER 特性を使用して定義されたストアドルーチン (プロシージャーおよび関数)

  • SQL SECURITY DEFINER 特性を使用して定義されたビュー

  • トリガーとイベント

このようなコンテキストでは、権限チェックは DEFINER アカウントと照合して実行され、CURRENT_USER() はそのアカウントを参照し、ストアドルーチンまたはビューを呼び出したクライアント、またはトリガーをアクティブにしたクライアントのアカウントは参照しません。 クライアントおよびクライアントの接続元ホストによって指定された実際のユーザー名を示す値を返す USER() 関数を呼び出すと、呼び出し元のユーザーを特定できます。 ただし、USER() の値にはワイルドカードが含まれない一方で、(CURRENT_USER() によって返される) アカウントの値にはユーザー名およびホスト名のワイルドカードが含まれる可能性があるため、この値は必ずしも、user テーブル内のアカウントに直接対応するとはかぎりません。

たとえば、空白のユーザー名は任意のユーザーに一致するため、''@'localhost' のアカウントを使用すると、クライアントは任意のユーザー名を持つローカルホストから匿名ユーザーとして接続できます。 この場合、クライアントがローカルホストから user1 として接続すると、USER()CURRENT_USER() は異なる値を返します:

mysql> SELECT USER(), CURRENT_USER();
+-----------------+----------------+
| USER()          | CURRENT_USER() |
+-----------------+----------------+
| user1@localhost | @localhost     |
+-----------------+----------------+

アカウントのホスト名部分にワイルドカードを含めることもできます。 ホスト名に'%'または'_'パターン文字が含まれているか、ネットマスク表記法を使用している場合、アカウントは複数のホストから接続しているクライアントに使用でき、CURRENT_USER() 値はどちらかを示しません。 たとえば、アカウント 'user2'@'%.example.com' を使用すると、user2example.com ドメイン内の任意のホストから接続できます。 user2remote.example.com から接続すると、USER()CURRENT_USER() は別々の値を返します。

mysql> SELECT USER(), CURRENT_USER();
+--------------------------+---------------------+
| USER()                   | CURRENT_USER()      |
+--------------------------+---------------------+
| user2@remote.example.com | user2@%.example.com |
+--------------------------+---------------------+

アプリケーションがユーザーを監査するために USER() を呼び出す必要があるが (たとえば、トリガー内から監査を実行する場合)、USER() の値を user テーブル内のアカウントに関連付けることができる必要もある場合は、アカウントの User または Host カラムにワイルドカードが含まれることを回避する必要があります。 特に、User を (匿名のユーザーアカウントが作成される) 空にすることは許可しないでください。また、Host の値に、パターン文字またはネットマスク表記を使用することも許可しないでください。 すべてのアカウントには、空でない User 値とリテラルの Host 値を含める必要があります。

前述の例に関しては、ワイルドカードが使用されないように ''@'localhost' および 'user2'@'%.example.com' アカウントを変更するようにしてください。

RENAME USER ''@'localhost' TO 'user1'@'localhost';
RENAME USER 'user2'@'%.example.com' TO 'user2'@'remote.example.com';

user2example.com ドメイン内の複数のホストから接続できる必要がある場合は、ホストごとに個別のアカウントにするべきです。

CURRENT_USER() または USER() の値からユーザー名またはホスト名の部分を抽出するには、SUBSTRING_INDEX() 関数を使用します。

mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',1);
+---------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',1) |
+---------------------------------------+
| user1                                 |
+---------------------------------------+

mysql> SELECT SUBSTRING_INDEX(CURRENT_USER(),'@',-1);
+----------------------------------------+
| SUBSTRING_INDEX(CURRENT_USER(),'@',-1) |
+----------------------------------------+
| localhost                              |
+----------------------------------------+

関連キーワード:  アカウント, 認証, 監査, 接続, ユーザー, パスワード, 関数, プラガブル, セキュリティー, user