MySQL運営ガイド

接続/要求の承認

接続の承認

MySQLサーバーに接続すると、まずサーバー接続の許可判定が行われます。もし身元が一致しない場合、接続を拒否し、接続許可した場合、サーバーはリクエストを待ちます。

身元は接続しようとしているホストMySQL ユーザー名に基づいて確認されます

身元の確認は、 user テーブルのスコープフィールド(Host, User, Password)を使用して行われます。

userテーブルのスコープフィールドの登録は以下のとおりです。

  • Host の値はホスト名か IP アドレスか 「localhost」。
  • Host にはワイルドカード文字のパーセント(%) とアンダーバー(_) が使用可能。
  • Host に % を設定すると、全てのホストにマッチする。 Host を空にすると、%
    と同じになる。これらの値は、どんなホストもサーバーに接続できるということになる。
  • ワイルドカード文字は User 項目に設定できないが、 User
    項目を空(ブランク)にすることはでる。空文字は全ての名前にマッチする。これはユーザー名がない状態で接続してきたものに適用され、クライアントがユーザー名を明記しない限り、匿名ユーザー(名前がブランク)として扱われる。全てのアクセスのチェックに空文字のユーザー名が使用される事を意味する。
  • Password 項目は空にできる。その場合、パスワードなして接続できることになる。

非ブランクの Password 値はパスワードを暗号化したものです。 MySQLはだれもが見れるようにパスワードをプレーンテキストでは保存しません。接続を試みようとしているユーザーのパスワードも(PASSWORD()関数で) 暗号化され、user テーブルに保存されている暗号化パスワードと比較されます。

以下は接続要求に対して与える、 user テーブルの Host と User の設定例です。

Hostの値 Userの値 Connections matched by entry
www.rfs.jp sv sv, www.rfs.jp から接続
www.rfs.jp '' www.rfs.jp から接続してくる全てのユーザー
% sv sv, 全てのホストから接続
% '' 全てのホストから接続してくる全ユーザー
%.rfs.jp sv sv, rfs.jp ドメイン内の全てのホストからの接続
x.y.% sv sv, x.y.net, x.y.com,x.y.edu, などからの接続
144.155.166.177 sv sv, IP address が 144.155.166.177
のホストからの接続
144.155.166.% sv sv, 144.155.166 class C subnet
内の全てのホストからの接続

Host に IP のワイルドカード(例えば '000.000.000.%'はサブネットの全てのホストにマッチ) を使用することができます。この場合、
000.000.000.somewhere.com というホスト名でだれかが接続しようとしてくることも考えられます。このような攻撃に対し、MySQLは数字やドットで始まるホスト名を拒否しています。もし 1.2.foo.comのような名前のホストを持っている場合、許可テーブルの Host には絶対にマッチしません。 IPアドレスのみ、IPのワイルドカードにマッチする事になります。

サーバーに来る接続は、user テーブル内の登録に1つ以上マッチする可能性があります。例えば、rfs.jpの svからの接続は、上に示された登録のうちのいくつかにマッチします。サーバーは、複数の登録にマッチした場合、最初にマッチした登録が使用されます。

user テーブルが以下のようにソートされていた場合です。

+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| % | root | ...
| % | staff | ...
| localhost | root | ...
| localhost | | ...
+-----------+----------+-

サーバーがこのテーブルを読むと、Hostに値が最も確実に特定できるホストを指定しているエントリを最初に参照します。

Host の値が同じエントリがあった場合、もっとも明確に Userの値がユーザーを指定しているエントリを最初に参照します。この結果、user テーブルは以下のようにソートされます。

+-----------+----------+-
| Host | User | ...
+-----------+----------+-
| localhost | root | ...
| localhost | | ...
| % | staff | ...
| % | root | ...
+-----------+----------+-

接続が試みられた場合、サーバーは並び換えられた登録を探し、最初に見つけたものを使用します。 "localhost"の jeffrey からの接続は、まず最初に Host に localhostを設定しているエントリにマッチします。ユーザー名が空のエントリは、ホスト名とユーザー名の両方を指定した接続にもマッチします('%'/'staff' エントリもマッチしますが、最初にはマッチしません)。

よくある過ちは、ユーザー名を与えた場合、サーバーが接続にマッチするものを探す際に、そのユーザーが登録されている全てのルールが、最初に使用されるだろうと考えることです。"rfs.jp"の "staff" からの接続が最初にマッチするのは、 User フィールドの値が "staff"になっているエントリではなく、ユーザー名なし(=だれでも) のエントリの方が先にマッチします。

もしサーバーへの接続がうまく行かない場合、 userテーブルを表示し、マニュアルでソートしてみて、どのエントリに最初にマッチするか試したほうが良いでしょう。


要求の承認

一度接続か確立されると、サーバーはこの接続から来るそれぞれの要求が許可されているかどうかをチェックします。チェックは実行しようとしている操作のタイプにより行います。その操作が許可テーブルのどの特権フィールドに当てはまるかを見ます。

userテーブルは全てに対して基本となる特権をユーザーに割り当てます。たとえカレントのデータベースが許可を与えていなくても、userテーブルの設定が優先されます。例えば、user テーブルで deleteを許可した場合、サーバーにあるどんなデータベースの行も削除できます。この特権はスーパーユーザー(サーバーやデーターベース管理者)のみに与えておく事が賢明です。ユーザーは、userテーブルの特権の設定を 'N' のままにしておくべきですし、また、db テーブルと hostテーブルを利用して、データベースを指定した上でユーザーに特権を許可すべきでしょう。

db テーブルと host テーブルは特定のデータベースに対する特権許可を行います。

  • ワイルドカード文字 `%' と `_' は Db テーブルと Host
    フィールドだけに使用できます。
  • '%' Host 値は ``あらゆるホスト'' を意味します。 db テーブルの Host
    に空を設定すると、``さらに host テーブルに許可情報を探しにいく'' となります。
  • '%' か 空値を Host テーブルに設定すると、それは ``あらゆるホスト'' となります。
  • '%' か 空値を host テーブルの Db フィールドに設定すると、それは
    ``あらゆるデータベース'' となります。
  • User を空値にすると、匿名ユーザーにマッチします。

サーバー起動時に、db テーブルと host テーブルはサーバーに読み込まれます。 (userテーブルもこの時に同時に読まれる) db テーブルは Host, Db, User のフィールドでソートされ、host テーブルは Host, Db フィールドでソートされます。 userテーブルは、一番特定できるエントリを最初に、一番特定できないものを最後にソートします。サーバーはソートされたものの中から、最初にマッチしたものを使用します。

tables_priv と columns_privテーブルは、特定のテーブルと項目に対する特権を許可します。スコープフィールドの値は、以下にそって記述されます。

  • ワイルドカード文字 `%' と `_' はどちらかのテーブルの Host 項目に使用できる。
  • どちらかのテーブルの Host 値を '%' かブランクにすると、 "any host."
    を意味する。
  • Db, Table_name, Column_name
    項目はどのテーブルにもワイルドカードやブランクは使用できない。

tables_priv と columns_priv テーブルは Host/Db/User項目で並び換えらます。これは db テーブルのソートに似ていますが、 Host項目だけがワイルドカードを含むので、ソートはより単純なものになります。

この要求の承認は次のようにして行います。もしアクセス承認を決定する部分のソースコードを理解できるなら、ちょっと変わったアルゴリズムで承認の決定を行っている事に気づくでしょう。

管理者の要求(shutdown, reload, etc.)については、サーバーは userテーブルだけを参照します。(userテーブルだけが管理者特権の項目を持つ)。エントリに許可登録されている操作は受け入れられ、それ以外は拒否されます。例えば、mysqladminshutdown を実行しようとしても、user テーブルの shutdown特権が許されていなければ実行できません。この時、db と hostテーブルはチェックされません。(これらのテーブルには Shutdown_priv カラムが無いからです)

データベースへの要求 (insert, update, etc.)において、サーバーはまず最初に、ユーザーのグローバルな特権(スーパーユーザー)を userの中から探しだします。もし許可が与えられていれば、アクセスは成功します。

userテーブルのグローバルな特権の設定が不十分であるなら、サーバーはユーザーのデータベースに対する特権を dbテーブルと host テーブルから決定します。

  • サーバーは db テーブルの Host,Db,Userフィールドを参照します。 Host とUser はユーザーの接続時のホスト名と MySQL ユーザー名にマッチします。 Dbフィールドはユーザーがアクセスしたいデータベース名にマッチします。 Host と Userにマッチするものが無かった場合、アクセスは拒否されます。
  • db テーブル内の Hostフィールドが空でないエントリにマッチした場合、ユーザーの指定されているデータベースに対する特権が定義されます。
  • Host フィールドが空値の dbテーブルのエントリにマッチした場合、どのホストがそのデータベースへアクセスできるかを host テーブルから探し出します。この場合、host テーブル の Host, Dbフィールドとマッチするものを探し出します。 hostテーブルにエントリがなかった場合、アクセスは拒否されます。もしマッチすると、ユーザーの特定データベースに対する特権は、host テーブルと db テーブル両方にまたがった特権から割り出されます。いうならば両方とも 'Y'である特権。 (この方法を使用すると、まず dbテーブルのエントリに大まかな特権を設定しておき、それから hostテーブルのエントリを使用して、ホスト情報もとに特権を限定していくという事ができます)

特定データベースに対する特権が db テーブルと hostテーブルのエントリから決定された後、サーバーはその割り出された特権に対し、userテーブルて設定されている特権を加えます。この結果から得られた特権にマッチした要求は受け入れられます。そうでなければ、サーバーはユーザーのテーブル、カラムに対する許可を、tables_priv と columns_priv 内に探します。アクセスはこの結果により、許可、拒否されます。

前のユーザの特権を計算する方法に関する記述は、 boolean で表すとするなら、以下のように表せます。

global privileges
OR (database privileges AND host privileges)
OR table privileges
OR column privileges

host テーブルは"安全な" ホストのリストを維持するために使用できます。

逆に host table で安全ではないホストを指定することもできます。  public.your.domainというマシンが安全ではない、公開されている場所にあるとします。その場合以下のようにして、その公開マシン以外のネットワーク上のホストに対して、アクセスを許可することができます。

+--------------------+----+-
| Host | Db | ...
+--------------------+----+-
| public.your.domain | % | ... (all privileges set to 'N')
| %.your.domain | % | ... (all privileges set to 'Y')
+--------------------+----+-


特権の変更が反映されるタイミング

mysqld の起動時、全ての許可テーブルはメモリーに読み込まれ、この時点で有効になります。

GRANT, REVOKE, SET PASSWORDを使用して許可テーブルを変更した場合、直にサーバに通知されます。

もし手動で許可テーブルを変更した場合(INSERT, UPDATE などで)、 FLUSH PRIVILEGES 構文か mysqladmin flush-privilegesコマンドを実行して、サーバーに許可テーブルの読み込みを指示します。そうしなければ、サーバーを再起動させるまで、変更は反映されません。

サーバーが許可テーブルの変更を通知した場合、既に接続しているクライアントは、以下のような影響を受けます。

  • テーブルと項目の許可の変更は、次のクライアントの要求から反映される。
  • データベースに対する許可の変更は次の USE db_name コマンド以降から有効になる。

グローバル特権とパスワードの変更は、次のクライアントの接続時から反映されます。

関連記事