接続/要求の承認

接続の承認

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

サーバーに来る接続は、user テーブル内の登録に1つ以上マッチするかもしれない。例えば, rfs.jp の sv からの接続は、上に示された登録のうちのいくつかにマッチする。サーバーは、複数の登録にマッチした場合、どのようにしてその中から使用する登録を選ぶのでしょう?サーバーは起動後に user テーブルをソートし、並び換えられた順に登録を検索することにより、この問題を解決する。最初にマッチした登録が使用される。

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 テーブルだけが管理者特権の項目を持つ)。エントリに許可登録されている操作は受け入れられ、それ以外は拒否される。例えば、mysqladmin shutdown を実行しようとしても、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

もし最初にグローバルな user エントリ特権がオペレーション要求に対して不十分である事がわかった場合に、サーバはあとから、それらの特権をデータベース特定、テーブル特定、コラム特定 特権に加えるのか、これはちょっとわからないかもしれない。

その理由は、ある要求が 1 つ以上のタイプの特権を必要とするかもしれないからだ。例えば、INSERT ... SELECT を実行するばあい、 insert , select 特権が必要だ。もしあなたの特権が、一つだけ user テーブルで許可されており、もう片方が db テーブルで許可されているする。この場合、そのリクエストを実行できる特権を持っているが、 サーバー自身がどちらのテーブルからか見分けることが出来ない。両方のエントリで与えられる特権は結合される。

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

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

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

特権のテーブル設定は、あなたの思い通りに許可が得られるのか、常に(mysqlaccess等を使用して)チェックすべきだ。


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

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

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

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

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

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

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

PAGE TOP

新着記事

タグクラウド

Smartからのお知らせ

関連サイト