ストアドプログラム (プロシージャ、ファンクション、トリガーおよびイベント) およびビューは、使用前に定義され、参照されると、権限を決定するセキュリティコンテキスト内で実行されます。 ストアドオブジェクトの実行に適用可能な権限は、その DEFINER
属性および SQL SECURITY
特性によって制御されます。
格納されたオブジェクト定義には、MySQL アカウントを指定する DEFINER
属性を含めることができます。 定義で DEFINER
属性が省略されている場合、デフォルトのオブジェクト定義者はそれを作成したユーザーです。
次のルールによって、格納されたオブジェクトの DEFINER
属性として指定できるアカウントが決定されます:
SET_USER_ID
権限 (または非推奨のSUPER
権限) がある場合は、任意のアカウントをDEFINER
属性として指定できます。 アカウントが存在しない場合は、警告が生成されます。 また、ストアドオブジェクトのDEFINER
属性をSYSTEM_USER
権限を持つアカウントに設定するには、SYSTEM_USER
権限が必要です。それ以外の場合、許可されるアカウントは、文字どおり、または
CURRENT_USER
またはCURRENT_USER()
として指定された独自のアカウントのみです。 定義者は他のアカウントに設定できません。
存在しない DEFINER
アカウントでストアドオブジェクトを作成すると、孤立したオブジェクトが作成され、負の結果になる可能性があります。孤立したストアドオブジェクト を参照してください。
ストアドルーチン (プロシージャおよびファンクション) およびビューの場合、オブジェクト定義に 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
アカウントが高い権限を持つ場合、オブジェクトは機密操作または危険な操作を実行できる可能性があります。 これは、オブジェクトの作成に必要な権限が、そのオブジェクトを作成したユーザーのアカウントから取り消された場合も当てはまります。 管理者は、特にユーザーへのオブジェクト作成権限の付与に注意する必要があります。