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


MySQL 8.0 リファレンスマニュアル  /  ストアドオブジェクト  /  ストアドオブジェクトのアクセス制御

25.6 ストアドオブジェクトのアクセス制御

ストアドプログラム (プロシージャ、ファンクション、トリガーおよびイベント) およびビューは、使用前に定義され、参照されると、権限を決定するセキュリティコンテキスト内で実行されます。 ストアドオブジェクトの実行に適用可能な権限は、その DEFINER 属性および SQL SECURITY 特性によって制御されます。

DEFINER 属性

格納されたオブジェクト定義には、MySQL アカウントを指定する DEFINER 属性を含めることができます。 定義で DEFINER 属性が省略されている場合、デフォルトのオブジェクト定義者はそれを作成したユーザーです。

次のルールによって、格納されたオブジェクトの DEFINER 属性として指定できるアカウントが決定されます:

  • SET_USER_ID 権限 (または非推奨の SUPER 権限) がある場合は、任意のアカウントを DEFINER 属性として指定できます。 アカウントが存在しない場合は、警告が生成されます。 また、ストアドオブジェクトの DEFINER 属性を SYSTEM_USER 権限を持つアカウントに設定するには、SYSTEM_USER 権限が必要です。

  • それ以外の場合、許可されるアカウントは、文字どおり、または CURRENT_USER または CURRENT_USER() として指定された独自のアカウントのみです。 定義者は他のアカウントに設定できません。

存在しない DEFINER アカウントでストアドオブジェクトを作成すると、孤立したオブジェクトが作成され、負の結果になる可能性があります。孤立したストアドオブジェクト を参照してください。

SQL SECURITY 特性

ストアドルーチン (プロシージャおよびファンクション) およびビューの場合、オブジェクト定義に DEFINER または INVOKER の値を持つ SQL SECURITY 特性を含めて、オブジェクトが定義者コンテキストで実行されるか起動側コンテキストで実行されるかを指定できます。 定義で SQL SECURITY 特性が省略されている場合、デフォルトは定義者コンテキストです。

トリガーとイベントには、SQL SECURITY 特性がなく、常に定義側のコンテキストで実行します。 サーバーが必要に応じて自動的にこれらのオブジェクトを呼び出すので、呼び出し元ユーザーは存在しません。

定義側と呼び出し元のセキュリティーのコンテキストは次のように異なります。

  • 定義者セキュリティコンテキストで実行されるストアドオブジェクトは、その DEFINER 属性で指定されたアカウントの権限で実行されます。 これらの権限は、呼び出し元ユーザーの権限とは完全に異なる場合があります。 実行者は、オブジェクトを参照する適切な権限 (たとえば、ストアドプロシージャをコールするための EXECUTE またはビューから選択する SELECT など) を持っている必要がありますが、オブジェクトの実行中、実行者権限は無視され、DEFINER アカウント権限のみが関係します。 DEFINER アカウントに少数の権限がある場合、オブジェクトは実行可能な操作に対応して制限されます。 DEFINER アカウントが高い権限を持つ場合 (管理アカウントなど)、オブジェクトは強力な操作誰が呼び出すかに関係なくを実行できます。

  • 呼び出し元のセキュリティーコンテキストで実行するストアドルーチンまたはビューは、呼び出し元が権限を持つ操作だけを実行できます。 DEFINER 属性はオブジェクトの実行には影響しません。

定義者セキュリティコンテキストで実行するために SQL SECURITY DEFINER で宣言されている次のストアドプロシージャについて考えてみます:

CREATE DEFINER = 'admin'@'localhost' PROCEDURE p1()
SQL SECURITY DEFINER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

p1 に対する EXECUTE 権限を持つどのユーザーでも、CALL ステートメントを使用してこれを呼び出すことができます。 ただし、p1 を実行すると、定義者セキュリティコンテキストで実行されるため、DEFINER 属性として指定されたアカウントである'admin'@'localhost'の権限で実行されます。 このアカウントには、p1 に対する EXECUTE 権限と、オブジェクト本体内で参照される t1 テーブルに対する UPDATE 権限が必要です。 それ以外の場合、プロシージャーは失敗します。

続いて次のストアドプロシージャーを検討してください。これは p1 と同じですが、その SQL SECURITY 特性が INVOKER である点が異なります。

CREATE DEFINER = 'admin'@'localhost' PROCEDURE p2()
SQL SECURITY INVOKER
BEGIN
  UPDATE t1 SET counter = counter + 1;
END;

p1 とは異なり、p2 は起動側セキュリティコンテキストで実行されるため、DEFINER 属性値に関係なく、起動側ユーザーの権限を使用します。実行者に p2 に対する EXECUTE 権限または t1 テーブルに対する UPDATE 権限がない場合、p2 は失敗します。

孤立したストアドオブジェクト

孤立したストアドオブジェクトは、その DEFINER 属性が存在しないアカウントを指定するオブジェクトです:

  • 孤立したストアドオブジェクトは、オブジェクトの作成時に存在しない DEFINER アカウントを指定することで作成できます。

  • 既存のストアドオブジェクトは、オブジェクトの DEFINER アカウントを削除する DROP USER ステートメント、またはオブジェクトの DEFINER アカウントの名前を変更する RENAME USER ステートメントの実行によって孤立する可能性があります。

孤立したストアドオブジェクトには、次のような問題がある可能性があります:

  • DEFINER アカウントが存在しないため、定義者セキュリティコンテキストで実行される場合、オブジェクトは予想どおりに動作しない可能性があります:

    • ストアドルーチンの場合、SQL SECURITY 値が DEFINER で定義者アカウントが存在しないと、ルーチンの実行時にエラーが発生します。

    • トリガーの場合、アカウントが実際に存在するまでトリガーのアクティブ化を行うことはお薦めしません。 それ以外の権限確認に関する動作は定義されていません。

    • イベントの場合、アカウントが存在しないと、イベントの実行時にエラーが発生します。

    • ビューでは、SQL SECURITY 値が DEFINER で定義者アカウントが存在しない場合にビューが参照されると、エラーが発生します。

  • その後、オブジェクトに関連しない目的で存在しない DEFINER アカウントが再作成されると、オブジェクトにセキュリティリスクが生じる可能性があります。 この場合、オブジェクトと適切な権限を持つアカウント「採用」は、意図していない場合でもオブジェクトを実行できます。

MySQL 8.0.22 の時点では、サーバーは、(おそらく誤って) 格納されたオブジェクトが孤立したり、現在孤立している格納されたオブジェクトを採用する原因となる操作を防ぐために設計された追加のアカウント管理セキュリティチェックを強制します:

  • 削除するアカウントが格納されたオブジェクトの DEFINER 属性として指定されている場合、DROP USER はエラーで失敗します。 (つまり、アカウントを削除すると、格納されたオブジェクトが孤立する場合、ステートメントは失敗します。)

  • 名前を変更するアカウントが格納されているオブジェクトの DEFINER 属性として指定されている場合、RENAME USER はエラーで失敗します。 (つまり、アカウントの名前を変更すると、格納されているオブジェクトが孤立する場合、ステートメントは失敗します。)

  • 作成するアカウントの名前が格納されたオブジェクトの DEFINER 属性として指定されている場合、CREATE USER はエラーで失敗します。 (つまり、アカウントを作成すると、アカウントが現在孤立しているストアドオブジェクトを採用する場合、ステートメントは失敗します。)

特定の状況では、これらのアカウント管理ステートメントは、それ以外の場合でも意図せずに実行する必要がある場合があります。 これを可能にするために、ユーザーが SET_USER_ID 権限を持っている場合、その権限は孤立したオブジェクトセキュリティチェックをオーバーライドし、ステートメントはエラーで失敗するのではなく警告で成功します。

MySQL インストールでストアドオブジェクト定義者として使用されるアカウントに関する情報を取得するには、INFORMATION_SCHEMA にクエリーします。

このクエリーは、DEFINER 属性を持つオブジェクトを記述する INFORMATION_SCHEMA テーブルを識別します:

mysql> SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.COLUMNS
       WHERE COLUMN_NAME = 'DEFINER';
+--------------------+------------+
| TABLE_SCHEMA       | TABLE_NAME |
+--------------------+------------+
| information_schema | EVENTS     |
| information_schema | ROUTINES   |
| information_schema | TRIGGERS   |
| information_schema | VIEWS      |
+--------------------+------------+

結果には、どのテーブルをクエリーして、どのストアドオブジェクト DEFINER 値が存在するか、およびどのオブジェクトが特定の DEFINER 値を持つかが示されます:

  • 各テーブルに存在する DEFINER 値を識別するには、次のクエリーを使用します:

    SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.EVENTS;
    SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.ROUTINES;
    SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.TRIGGERS;
    SELECT DISTINCT DEFINER FROM INFORMATION_SCHEMA.VIEWS;

    クエリー結果は、次のように表示されるすべてのアカウントにとって重要です:

    • アカウントが存在する場合、アカウントを削除または名前変更すると、格納されているオブジェクトが孤立します。 アカウントを削除または名前変更する場合は、まず、関連付けられているストアドオブジェクトを削除するか、別の定義者を持つように再定義することを検討してください。

    • アカウントが存在しない場合は作成すると、現在孤立している格納済オブジェクトが採用されます。 アカウントを作成する場合は、孤立したオブジェクトを関連付けるかどうかを検討してください。 そうでない場合は、別の定義者を持つように再定義します。

    別の定義者でオブジェクトを再定義するには、ALTER EVENT または ALTER VIEW を使用して、イベントおよびビューの DEFINER アカウントを直接変更できます。 ストアドプロシージャとストアドファンクションおよびトリガーの場合は、オブジェクトを削除して再作成し、別の DEFINER アカウントを割り当てる必要があります

  • 特定の DEFINER アカウントを持つオブジェクトを識別するには、次のクエリーを使用して、対象のアカウントを user_name@host_name に置き換えます:

    SELECT EVENT_SCHEMA, EVENT_NAME FROM INFORMATION_SCHEMA.EVENTS
    WHERE DEFINER = 'user_name@host_name';
    SELECT ROUTINE_SCHEMA, ROUTINE_NAME, ROUTINE_TYPE
    FROM INFORMATION_SCHEMA.ROUTINES
    WHERE DEFINER = 'user_name@host_name';
    SELECT TRIGGER_SCHEMA, TRIGGER_NAME FROM INFORMATION_SCHEMA.TRIGGERS
    WHERE DEFINER = 'user_name@host_name';
    SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS
    WHERE DEFINER = 'user_name@host_name';

    ROUTINES テーブルの場合、クエリーには ROUTINE_TYPE カラムが含まれるため、出力行は DEFINER がストアドプロシージャ用かストアドファンクション用かを区別します。

    検索するアカウントが存在しない場合、それらのクエリーによって表示されるオブジェクトは孤立したオブジェクトです。

リスク最小化のガイドライン

ストアドオブジェクトの作成および使用のリスクを最小限に抑えるには、次のガイドラインに従います:

  • 孤立したストアドオブジェクト (DEFINER 属性が存在しないアカウントを指定するオブジェクト) は作成しないでください。 既存のオブジェクトの DEFINER 属性で指定されたアカウントを削除または名前変更して、格納されたオブジェクトを孤立させないでください。

  • 可能な場合は、ストアドルーチンまたはビューに対して、オブジェクト定義の SQL SECURITY INVOKER を使用して、オブジェクトが実行する操作に適したアクセス許可を持つユーザーだけが使用できるようにします。

  • SET_USER_ID 権限 (または非推奨の SUPER 権限) を持つアカウントの使用中に定義者コンテキストストアドオブジェクトを作成する場合は、オブジェクトで実行される操作に必要な権限のみを持つアカウントを指定する明示的な DEFINER 属性を指定します。 高い権限を持つ DEFINER アカウントは、絶対に必要な場合にのみ指定してください。

  • 管理者は、SET_USER_ID 権限 (または非推奨の SUPER 権限) を付与しないことで、高い権限を持つ DEFINER アカウントを指定するストアドオブジェクトをユーザーが作成できないようにできます。

  • 定義側のコンテキストのオブジェクトを作成するときには、呼び出し元ユーザーに権限のないデータに定義側がアクセスできる場合があります。 場合によっては、権限のないユーザーに特定の権限を付与しないことで、これらのオブジェクトへの参照を防止できます:

    • ストアドルーチンに対する EXECUTE 権限を持たないユーザーは、ストアドルーチンを参照できません。

    • ビューに対する適切な権限 (ビューから選択するための SELECT、ビューに挿入するための INSERT など) を持っていないユーザーは、ビューを参照できません。

    ただし、トリガーおよびイベントは常に定義者コンテキストで実行されるため、これらのコントロールは存在しません。 サーバーは必要に応じてこれらのオブジェクトを自動的に呼び出し、ユーザーはこれらを直接参照しません:

    • トリガーは、トリガーが関連付けられているテーブルへのアクセスによってアクティブ化されます。特別な権限を持たないユーザーによる通常のテーブルアクセスでもアクティブ化されます。

    • イベントは、スケジュールに基づいてサーバーによって実行されます。

    どちらの場合も、DEFINER アカウントが高い権限を持つ場合、オブジェクトは機密操作または危険な操作を実行できる可能性があります。 これは、オブジェクトの作成に必要な権限が、そのオブジェクトを作成したユーザーのアカウントから取り消された場合も当てはまります。 管理者は、特にユーザーへのオブジェクト作成権限の付与に注意する必要があります。


関連キーワード:  アカウント, DEFINER, オブジェクト, 権限, 実行, 定義, ストアドオブジェクト, 属性, 孤立, 作成