Go to the first, previous, next, last section, table of contents.


6 MySQL 特権はどのように動くか?

MySQL は先進的な非標準のセキュリティ/特権システムを持っています。 本章ではどのようにそれが動くかを述べます。

6.1 特権システムの行うこと

MySQL 特権システムの基本機能は、与えられたホストから接続する ユーザを認証すること、そしてデータベースの select, insert, update, delete 特権を与えることです。

拡張機能は匿名ユーザをもつ能力を含み、LOAD DATA INFILE のような MySQL 固有の機能を使用する許可を与えます。

6.2 MySQL ユーザ名とパスワード

MySQL によって使用されるユーザー名とパスワードの使用のされ方と、 UNIX, Windows で使用される方法とは、いくつか異なる点があります。

6.3 MySQL サーバーに接続

MySQL クライアントプログラムは、共通の決まった引数を持ちます: 接続したいホスト名、接続ユーザー名、そしてパスワードです。 例えば、mysql コマンドは以下のような引数を持ちます (オプションの引数は `['`]' で囲まれている部分です)

shell> mysql [-h host_name] [-u user_name] [-pyour_pass]

-h, -u, -p オプションは以下と等価です。 --host=host_name, --user=user_name, --password=your_pass -p とパスワードの間にはスペースがないことに注意

注意: コマンドラインにパスワードを与えるのは安全ではありません! システムに入っている如何なるユーザーも ps auxww のようなコマンドを 使用する事でパスワードを見付ける事ができます 「4.15.4 オプションファイル ( my.cnf )」節参照.

mysql コマンドはコマンドラインに引数がなければ接続にデフォルト値を用います。

Unix のログインユーザーが joe の場合、以下のコマンドは等価です:

shell> mysql -h localhost -u joe
shell> mysql -h localhost
shell> mysql -u joe
shell> mysql

他の MySQL クライアントも同じように動作します。

Unix システムでは、ある値をデフォルト値にして接続に使用することができます。 そうすることにそり、毎回毎回コマンドラインに引数を与えなくてすむようになります:

もし接続のためのパラメターの設定が複数重なっていた場合、コマンドラインに与えられた値が、 設定ファイルに書かれたものと環境変数をを上書きします。 設定ファイルに書かれた値は、環境変数で与えられたものを上書きします。

6.3.1 パスワードを安全にする

自分のパスワードを他人にさらけ出すのは勧められることではありません。 それぞれの方法に於ける危険度に応じ、以下に示す方法でクライアントプログラムに あなたのパスワードをあたえて走らせることができます:

まとめると、より安全な方法は、 パスワードプロンプトを返すクライアントプログラムを実行するか、 適切なパーミッションをかけた `.my.cnf' ファイルにパスワードを書くか です。

6.4 MySQL が提供する特権

特権の設定は mysql データベースの user, db, host, tables_priv, columns_priv で行います。 (mysql はデータベースの名前です) MySQL サーバーは、サーバーの起動時か 「6.8 いつ特権の変更が反映されるか」節 で説明されている方法により、 これらのテーブルから特権の設定を読み込みます。

MySQL が提供する特権の名称は, 本マニュアルでは以下の表の名称を用います。 この表の項目名がそれぞれの許可される特権とその説明に対応しています:

Privilege Column Context
select Select_priv tables
insert Insert_priv tables
update Update_priv tables
delete Delete_priv tables
index Index_priv tables
alter Alter_priv tables
create Create_priv databases, tables or indexes
drop Drop_priv databases or tables
grant Grant_priv databases or tables
references References_priv databases or tables
reload Reload_priv server administration
shutdown Shutdown_priv server administration
process Process_priv server administration
file File_priv file access on server

select, insert, update, delete の特権は、 存在しているデータベースのテーブルに対して許可されます。

もしテーブルから行を取り出すだけなら、SELECT 構文を実行するためには select 特権だけあればかまいません。 だけでなく、サーバーのどのデータベースにアクセスを許可されていない場合でも、 ある種の SELECT は実行することができます。 例えば、簡単な計算を mysql クライアントで行う場合です:

mysql> SELECT 1+1;
mysql> SELECT PI()*2;

index 特権はインデックスの作成と破棄(削除)を許可します。

alter 特権は ALTER TABLE の実行を許可します。

createdrop 特権は、新しいデータベースやテーブルの作成、 あるいは既に存在するデータベース、テーブルの破棄(削除)を許可します。

注意: mysql データベースに登録されているユーザーに drop 権限を与えると、 そのユーザーは MySQL のアクセス特権が格納されているデータベースを破棄できます!

grant 特権は、あなたが他のユーザーに対して自分の特権を持たせる事を許可します。

file の特権を与えると、LOAD DATA INFILESELECT ... INTO OUTFILE 構文を使用して、サーバーのファイルを読み書きする事ができます。 MySQL サーバーがが読み書きできるファイルに対して、この特権が与えられたユーザーはファイルを読み書きできます。

残りの特権はアドミン操作に関する許可で、mysqladmin コマンドを使用して実行します。 次の表に mysqladmin コマンドのどれが、どの特権に対応しているかを示します:

Privilege Commands permitted to privilege holders
reload reload, refresh, flush-privileges, flush-hosts, flush-logs, flush-tables
shutdown shutdown
process processlist, kill

reload コマンドはサーバーに特権の設定を再読込させるように伝えます。 refresh コマンドは全てのテーブルをフラッシュし、ログファイルを開き直します。 flush-privilegesreload と同義です。 その他の flush-* コマンドは refresh の動作とよく似ていますが、 適用範囲を絞っており、ちょっとした場合に有効です。 例えば、ログファイルだけをフラッシュしたい場合、 refresh を行うよりも flush-logs がいいです。

shutdown コマンドは、サーバーをシャットダウンします。

processlist コマンドはサーバーが実行しているスレッドの情報を表示します。 kill コマンドはサーバーのスレッドをkillします。 自分のスレッドは常に表示、killできますが、他人のスレッドをそうするには process 特権が必要です。

ある特権を欲しがるユーザーだけにその特権を許可するのはよい考えですが、 特権を与えるときには、特定の事項を熟知していなければなりません:

以下は MySQL の特権システムで行うものではありません:

6.5 特権システムはどのように動くか?

MySQL の特権システムは、全てのユーザーが与えられた許可の範囲内で動く事を保証します。 MySQL サーバーに接続するとき、本人の身元は、接続元のホスト接続に使用するユーザー名 によって確認されます。 このシステムは、あなたの身元とあなたが要求することが何か によって、特権を与えます。

MySQL はあなたのホスト名とユーザー名の両方をあわせてチェックします。 これはインターネット上に同じ名前のユーザーがどこかにいるかもしれないということからそうしています。 例えば、whitehouse.gov から接続してきた bill と、 mosoft.com から接続してきた bill は同一人物である必要はありません。 MySQL はこの違うホストから接続してきた同名のユーザーを以下のようにして扱います: whitehouse.gov から接続した bill にある許可をあたえ、 それとは違う許可を mosoft.com から接続してきた bill に与えます。

MySQL のアクセスコントロールは以下の二つからなります:

サーバーは mysql データベースの user, db, host 3つのテーブルから、 この2つのアクセス制限を決定します。 このテーブルのフィールドは以下のようになっています:

Table name user db host
Scope fields Host Host Host
User Db Db
Password User
Privilege fields Select_priv Select_priv Select_priv
Insert_priv Insert_priv Insert_priv
Update_priv Update_priv Update_priv
Delete_priv Delete_priv Delete_priv
Index_priv Index_priv Index_priv
Alter_priv Alter_priv Alter_priv
Create_priv Create_priv Create_priv
Drop_priv Drop_priv Drop_priv
Grant_priv Grant_priv Grant_priv
Reload_priv
Shutdown_priv
Process_priv
File_priv

 アクセスコントロールの第2段階(要求承認)のために、サーバーはこれら 3 つの テーブルによって決められた許可を基本としますが、もしテーブルに対する要求で あるならば、tables_privcolumns_priv テーブルを さらに調べます。これらのテーブルのフィールドは以下のようになっています:

Table name tables_priv columns_priv
Scope fields Host Host
Db Db
User User
Table_name Table_name
Column_name
Privilege fields Table_priv Type
Column_priv
Other fields Timestamp Timestamp
Grantor

 テーブルの各項目を分類すると、2種類にわかれます: 適用範囲を指定する項目(以下 スコープフィールド)と許可を定義する項目(以下 特権フィールド)です。

 スコープフィールドは、特権テーブルの登録ごとに、その適用範囲を決めます。 例えば、 user テーブルの HostUser'thomas.loc.gov''bob' が登録されている場合、 サーバーへの接続は ホスト thomas.loc.gov から来た 'bob' に許可されます。 同様に、db テーブルの Host, User, Db'thomas.loc.gov', 'bob', 'reports' が登録されていると、 ホスト thomas.loc.gov から来た bob に対し reports データベースへの接続が許されます。 tables_privcolumns_priv テーブルは、 テーブルか、テーブルとフィールドを対にしたスコープフィールドを含みます。

 アクセスのチェックは、Host の値はケース非依存で比較されます。 User, Password, Db, Table_name の値はケース依存で比較されます。 Column_name の値は MySQL 3.22.12 以上ではケース非依存で比較されます。 (3.22.11 までは ケース依存です)

特権フィールドは、テーブルに登録されることにより有効になった許可をしめし、 これはどの操作が実行できるかを示します。 サーバーは許可テーブルの情報をユーザーの特権を得るためにまとめます。 このユーザーの特権許可を割り出す方法は 「6.7 Access control, stage 2: 要求の承認」節 に述べておきます。

スコープフィールドは文字で定義され、デフォルト値は空文字になっています:

Field name Type
Host CHAR(60)
User CHAR(16)
Password CHAR(16)
Db CHAR(64) (CHAR(60) for the tables_priv and columns_priv tables)

user, db, host テーブルでは、 全ての特権フィールドは ENUM('N','Y') で定義されます。 この値は 'N''Y' のどちらかで、デフォルト値は 'N' です。

tables_privcolumns_priv テーブルでは、 特権フィールドは SET フィールドとして定義されます:

Table name Field name Possible set elements
tables_priv Table_priv 'Select', 'Insert', 'Update', 'Delete', 'Create', 'Drop', 'Grant', 'References', 'Index', 'Alter'
tables_priv Column_priv 'Select', 'Insert', 'Update', 'References'
columns_priv column_priv 'Select', 'Insert', 'Update', 'References'

サーバーは以下のように許可テーブルを使用します:

管理者特権 (reload, shutdown,など) は user テーブルにだけ定義するように。 これは、管理者操作はデータベースではなくサーバーへの操作であり、 他の許可テーブルにある必要がないからです。 またこうしておくと、管理者操作の許可は、user テーブルの定義だけを 見ればわかるようになります。

file 操作の特権は user テーブルにだけ定義するように。 これは管理者操作ではありませんが、アクセスしているデータベースにかかわらず、 サーバー内のファイルを読み書きできるのです。

mysqld サーバーは起動時にこれらのテーブルを読み込みます。 許可テーブルの変更を反映させる方法はこちらを参照のこと → 「6.8 いつ特権の変更が反映されるか」節

これらのテーブルの登録を変更した場合、思ったとおりの特権状態になっている事を確認することはいいことです。 問題の解決には, 「6.12 何故 Access denied エラーになるのか」節. セキュリティに関するアドバイスは 「6.13 MySQL をクラッカーに対して安全にする方法」節.

便利なツールとして mysqlaccess スクリプト( Yves Carlier 作)が MySQL の配布に含まれています。 mysqlaccess--help オプションで起動するとヘルプが表示されます。 mysqlaccessuser,db and host テーブルだけしか 検査しません。テーブルレベルの特権、フィールドレベルの特権は調べません。

6.6 Access control, stage 1: 接続の承認

MySQL サーバーに接続すると、あなたがパスワード認証して接続していようがいまいが、 サーバーはあなたの身元により接続の許可拒否を行います。 もし身元が一致しない場合接続を拒否し、接続許可した場合、サーバーは stage 2 へと進み、要求を待ちます。

身元は二つのものに基づいて確認されます:

身元の確認は user テーブルのスコープフィールド(Host, User, Password) を使用して行います。 サーバーは user テーブルの登録に一致しているホスト名とユーザー名に限り接続を許可し、その後、パスワードを要求します。

user テーブルのスコープフィールドの登録は以下のようになります:

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

以下の表は、接続要求に対して与える、 user テーブルの HostUser の設定例です:

Host value User value Connections matched by entry
'thomas.loc.gov' 'fred' fred, thomas.loc.gov から接続
'thomas.loc.gov' '' thomas.loc.gov から接続してくる全てのユーザー
'%' 'fred' fred, 全てのホストから接続
'%' '' 全てのホストから接続してくる全ユーザー
'%.loc.gov' 'fred' fred, loc.gov ドメイン内の全てのホストからの接続
'x.y.%' 'fred' fred, x.y.net, x.y.com,x.y.edu, などからの接続. (あまり有効な使い方ではないです)
'144.155.166.177' 'fred' fred, IP address が 144.155.166.177 のホストからの接続
'144.155.166.%' 'fred' fred, 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つ以上 マッチするかもしれません。 例えば, thomas.loc.govfred からの接続は、上に示された 登録のうちのいくつかにマッチするでしょう。 サーバーは、複数の登録にマッチした場合、どのようにしてその中から 使用する登録を選ぶのでしょう? サーバーは起動後に user テーブルをソートし、並び換えられた順に 登録を検索することにより、この問題を解決します。 最初にマッチした登録が使用されます。

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

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

サーバーがこのテーブルを読むと、Host に値が最も確実に特定できるホストを指定しているエントリを、最初に参照します。 (Host 項の '%' は ``すべてのホスト'' を意味し、ホスト名をはっきりと特定しているものではありません)

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

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

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

もう一例。user が以下の設定と仮定します:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| %              | jeffrey  | ...
| thomas.loc.gov |          | ...
+----------------+----------+-

これは次のようにソートされます:

+----------------+----------+-
| Host           | User     | ...
+----------------+----------+-
| thomas.loc.gov |          | ...
| %              | jeffrey  | ...
+----------------+----------+-

thomas.loc.govjeffrey からの接続は、最初のエントリにマッチし、 whitehouse.govjeffrey からの接続は、二つ目のエントリにマッチします。

最初にサーバが,接続のためのマッチを見つけるのを試みるとき,共通の誤解は与えられた ユーザ名に明らかにそのユーザを命名するすべてのエントリが使用されると思うことです. これは単に本当ではありません. jeffreyによるthomas.loc.govからの接続が最初に エントリによってユーザ分野値として‘jeffrey'を含まないいずれのエントリによってる合わ せられる場合,前の例はこれをユーザ名なしで例示します!

よくある考え違いは、ユーザー名を与えた場合、 サーバーが接続にマッチするものを探す際に、 そのユーザーが登録されている全てのルールが、 最初に使用されるだろうと考えることです。これは正しくありません。 前の例でこれを示しましたが、thomas.loc.govjeffrey からの接続が 最初にマッチするのは、 User フィールドの値が 'jeffrey' に なっているエントリではなく、ユーザー名なし(=だれでも) のエントリの方が 先にマッチします!

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

6.7 Access control, stage 2: 要求の承認

一度接続か確立されると、サーバーはステージ2に移ります。 このステージでは、サーバーはこの接続から来るそれぞれの要求が許可されているかどうかをチェックします。 チェックは実行しようとしている操作のタイプにより行います。 その操作が許可テーブルのどの特権フィールドに当てはまるかを見ます。 これら特権は user, db,host, tables_privcolumns_priv テーブルより導出されます。 許可テーブルは GRANT コマンドで操作します。 「7.26 GRANTREVOKE 構文」節参照. (You may find it helpful to refer to the table shown earlier that lists the fields present in each of the grant tables; see 「6.5 特権システムはどのように動くか?」節.)

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

db テーブルと host テーブルは特定のデータベースに対する特権許可を行います。 Values in the scope fields may be specified as follows:

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

tables_privcolumns_priv テーブルは、 特定のテーブルとフィールドに対する特権を許可します。 スコープフィールドの値は、いかにそって記述されます:

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

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

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

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

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

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

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

先のユーザーの特権が計算される方法の記述は、boolean 表記で示すならば、 以下のようになるでしょう:

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

これは少し分かりにくいかもしれません。もしグローバルの user エントリ 特権許可が、リクエストされたオペレーションには不十分だと最初に分かった際、 サーバーがこれらの特権を database-, table-, column-固有の特権の 後に、なぜ、追加してしまうのか。 その理由は、リクエストが1個以上の特権を要求するだろうということです。 例えば、もしあなたが INSERT ... SELECT 構文を実行するなら、 あなたには insertselect 許可が必要です。 あなたの特権が、 user テーブルエントリで一つの特権が許可され、 db テーブルで、そのほかの特権が許可されていたとします。 この場合、あなたは、そのリクエストを実行するために、必要な特権を持っています。 しかし、サーバーはどちらのテーブル、それ単体からでは、特権を得ることが出来ません。 特権は、両方のエントリーを合わせるなくてはならないのです。

host テーブルは ``安全な'' ホストのリストを維持するために使用できます。 TcX では、host テーブルにはローカルネット上の全てのホストが登録されています。 これらのホストは全ての特権が許可されています。

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

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

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

6.8 いつ特権の変更が反映されるか

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

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

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

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

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

6.9 MySQL 特権許可の初期設定

MySQL インストール後、scripts/mysql_install_db を実行して特権のアクセス許可を初期化します。 「4.7.1 素早いインストールの概要」節参照. scripts/mysql_install_db スクリプトは mysqld サーバーを起動し、 以下のように特権を初期化してテーブルに登録します:

注意: デフォルトの特権は Win32 では違います。 「4.12.4 Win32 上で MySQL を実行」節参照.

初期インストールの状態ではかなりアクセスが解放されているので、 インストール後最初にすることは、MySQL root ユーザーにパスワードを設定することです。 以下のようにします(パスワードは PASSWORD() 関数を使用することをお忘れなく):

shell> mysql -u root mysql
mysql> UPDATE user SET Password=PASSWORD('new_password')
           WHERE user='root';
mysql> FLUSH PRIVILEGES;

MySQL 3.22 以上では、SET PASSWORD 構文も使用できます:

shell> mysql -u root mysql
mysql> SET PASSWORD FOR root=PASSWORD('new_password');

password をセットする他の方法として、mysqladmin コマンドも使用できます:

shell> mysqladmin -u root password new_password

もし最初の方法で user テーブルのパスワードを直接更新したなら、 サーバーに許可テーブルの再読み込みを行わせなければなりません(FLUSH PRIVILEGES を使用して)。

一度 root のパスワードを設定したなら、root でサーバーに接続する場合は 常にパスワードを与えなければなりません。

追加設定やテストをしているためパスワードを入れたくない場合、 root パスワードをブランクのままにしておこうと考えるかも知れませんが、 実稼働させる前には必ず設定してください。

どのようにデフォルトの特権を設定しているか、scripts/mysql_install_db 見てみてください。 これは他のユーザーを設定するときに使えるでしょう。

もし特権の初期状態を違うものにして初期化したいなら、 mysql_install_db を実行する前に編集してもよいでしょう。

もしテーブルを完全に作り直したいなら、mysql データベースのディレクトリに存在する 全ての `*.frm', `*.MYI', `*.MYD' ファイルを削除します。 (このディレクトリーはデータベースディレクトリーの下に mysql という名前で存在します。 mysqld --help とすればデータベースのディレクトリーが表示されます。) そして好みの許可状態に mysql_install_db を編集してから実行します。

注意: MySQL 3.22.10 以前のバージョンでは, `*.frm' ファイルを消してはいけません. もしうっかり消してしまった場合、 mysql_install_db を実行する前に、 MySQL 配布からコピーしなおさ なくてはなりません。

6.10 新しいユーザ特権を MySQL へ追加

ユーザーは2つの違った方法で追加できます: GRANT 構文を使用して行う方法と、 MySQL の許可テーブルを直接操作する方法とです。 GRANT 構文の使用をお勧めします。

以下の例では、いかにして mysql クライアントを使用して新規にユーザーを登録するかを示します。 以下の例では、特権は前節で述べたデフォルト値になっているとします。 よって変更を行うためには、あなたは mysqld が走っているマシン上にログインしていなくてはなりませんし、 かつ、MySQL root ユーザーで接続していなければなりません。 さらに MySQL root ユーザーには mysql データベースに対して insert 権限を持ち、 reload のアドミニストレーター特権を持っていなければなりません。 もし root ユーザーのパスワードを変えていたならば、 mysql コマンドにパスワード指定を与えなくてはなりません。

shell> mysql --user=root mysql
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@localhost
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT ALL PRIVILEGES ON *.* TO monty@"%"
           IDENTIFIED BY 'something' WITH GRANT OPTION;
mysql> GRANT RELOAD,PROCESS ON *.* TO admin@localhost;
mysql> GRANT USAGE ON *.* TO dummy@localhost;

これら GRANT 構文では3つの新しいユーザを作ります:

monty
どこからでもサーバーに接続できる完全なスーパーユーザ。 しかし、MySQL を使用する時にはパスワードを使用する必要があります。 monty@localhostmonty@"%" の両方に GRANT 構文を 発行しなくてはならない事に注意してください。 もし localhost からの許可をした登録がないと、localhost から接続した時、 mysql_install_db が自動で作成した localhost への匿名ユーザーが優先されます。 なぜなら、 Host フィールドの値が(ブランクやワールドカード以外に)明記されており、 許可登録が MySQL 内部でソートされる時に順番が上にソートされるからです。
admin
localhost からパスワードなしで接続できますが、reload, process の使用だけが許されます。 これは、mysqladmin reload, mysqladmin refresh, mysqladmin flush-* そして mysqladmin processlist コマンドの実行がこのユーザーに許可されます。 データベースへのアクセスは許可されていません。 しかしこれは後でテーブル GRANT 構文を発行すれば、 個々のデータベースへのアクセス特権が設定できます。
dummy
パスワードなしで localhost からのみ、接続できるユーザー。 グローバルな特権は全て 'N' に設定されます。 USAGE 特権は特権無しユーザーの設定を許可する事になります。 これは、特定データーベースに対しての許可を後から与える事を想定しています。

同じアクセス許可を INSERT 構文を使用して直接設定できます。 サーバーに許可テーブルの再読み込みを指示します:

shell> mysql --user=root mysql
mysql> INSERT INTO user VALUES('localhost','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user VALUES('%','monty',PASSWORD('something'),
                'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y')
mysql> INSERT INTO user SET Host='localhost',User='admin',
                 Reload_priv='Y', Process_priv='Y';
mysql> INSERT INTO user (Host,User,Password)
                        VALUES('localhost','dummy','');
mysql> FLUSH PRIVILEGES;

MySQL のバージョンにより、上の 'Y' の数が違う事に注意してください。 (3.22.11 以前のバージョンでは項目数が少なくなります). admin ユーザーを登録で使用している INSERT の拡張は 3.22.11 以上で可能です。

スーパーユーザーを定義するためには、user テーブルの許可フィールドを 'Y' にするだけでかまいません。 dbhost テーブルに登録は必要無いのです。

user テーブルの許可フィールドは最後の INSERT 文で(dummy ユーザーのために) は設定されていません。これらのフィールドはデフォルト値の 'N' になります。 これは GRANT USAGE が行うのと同じものです。

以下は、localhost, server.domain, whitehouse.gov から接続が可能な custom ユーザーの追加例です。 custom ユーザーは bankaccount データーベースには localhost からの接続のみを許可され、 expenses データベースには whitehouse.gov からのみ接続が許可され、 customer データベースには全てのホストから接続できます。 custom ユーザーは、 stupid というパスワードを全てのホストで使用したいとします。

このユーザーの許可を GRANT 構文で定義するには、以下のようにします:

shell> mysql --user=root mysql
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON bankaccount.*
           TO custom@localhost
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON expenses.*
           TO custom@whitehouse.gov
           IDENTIFIED BY 'stupid';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP
           ON customer.*
           TO custom@'%'
           IDENTIFIED BY 'stupid';

許可テーブルを直接変更してこのユーザーの特権を設定するにはいかのようにします (FLUSH PRIVILEGES を最後に実行している事に注意):

shell> mysql --user=root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES('localhost','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('server.domain','custom',PASSWORD('stupid'));
mysql> INSERT INTO user (Host,User,Password)
       VALUES('whitehouse.gov','custom',PASSWORD('stupid'));
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('localhost','bankaccount','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES
       ('whitehouse.gov','expenses','custom','Y','Y','Y','Y','Y','Y');
mysql> INSERT INTO db
       (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,
        Create_priv,Drop_priv)
       VALUES('%','customer','custom','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;

最初の3つの INSERT 文は、 custom ユーザーがそれぞれのホストから パスワードつきで接続できるように user テーブルに追加しています。 しかしここでは特権は1つも与えられていません(特権のデフォルト値は 'N' です)。 次の三つの INSERT 文は、bankaccount, expenses, customer データベースに対する該当ホストからのアクセス許可を custom ユーザーに与えるように、 db テーブルに追加しています。 許可テーブルが直接変更された場合、これらをサーバーに反映させるために、許可テーブルの 再読み込みを(FLUSH PRIVILEGESで) サーバーにつげなければなりません。

もし、あるドメインの全てのマシンに接続を許可したい場合、 以下のように GRANT 構文を発行します:

mysql> GRANT ...
           ON *.*
           TO myusername@"%.mydomainname.com"
           IDENTIFIED BY 'mypassword';

許可テーブルを直接変更するには以下のようにします:

mysql> INSERT INTO user VALUES ('%.mydomainname.com', 'myusername', 
           PASSWORD('mypassword'),...);
mysql> FLUSH PRIVILEGES;

もちろん、xmysqladmin, mysql_webadmin, そして xmysql を使って も、特権テーブルへの値の挿入/変更/更新ができます。これらのユーティリティは MySQL Contrib directory. に見つけることができます。

6.11 パスワードの設定法

前節の例で述べた、とても重要な基本原則:

INSERTUPDATE で空ではないパスワードを設定する場合、 暗号化するために PASSWORD() 関数を使用しなくてはなりません。 これは user テーブルはプレーンテキストでなく、暗号化されたパスワードであることを要求しているからです。 この原則を忘れてしまった場合、以下のようにしてパスワードをセットしてしまうかもしれません:

shell> mysql -u root mysql
mysql> INSERT INTO user (Host,User,Password)
       VALUES('%','jeffrey','biscuit');
mysql> FLUSH PRIVILEGES;

これは user テーブルにプレーンテキストの 'biscuit' をパスワードとして登録してしまいます。 jeffrey ユーザーでこのパスワードを使用してサーバーに接続しようとすると、 mysql クライアントは暗号化したパスワードをサーバーに送ります。 サーバーは暗号化されたパスワード('biscuit' ではありません) と user テーブルに登録された値('biscuit') を比較します。 その結果、比較は失敗し、サーバーは接続を拒否します:

shell> mysql -u jeffrey -pbiscuit test
Access denied

user テーブルに登録されるパスワードは暗号化されたものでなくてはなりません。 INSERT 構文は以下のようにして使用しなくてはなりません:

mysql> INSERT INTO user (Host,User,Password)
       VALUES('%','jeffrey',PASSWORD('biscuit'));

SET PASSWORD 構文を使用する場合は、以下のようにしなくてはなりません:

mysql> SET PASSWORD FOR jeffrey@"%" = PASSWORD('biscuit');

もし GRANT ... IDENTIFIED BY 構文や mysqladmin password コマンド でパスワードを設定した場合、PASSWORD() 関数は必要ありません。 両方とも、パスワードを暗号化してくれますので、 以下のように'biscuit'と与えます:

mysql> GRANT USAGE ON *.* TO jeffrey@"%" IDENTIFIED BY 'biscuit';

shell> mysqladmin -u jeffrey password biscuit

PASSWORD() がパスワードを暗号化することに注意してください。 この暗号化は UNIX のパスワードで使用されている暗号化と違うことにも留意してください。 UNIX パスワードファイルに記録されている暗号と PASSWORD() が暗号化した物が同じでも、 同じパスワードであるとは思わないでください。 「6.2 MySQL ユーザ名とパスワード」節参照.

6.12 何故 Access denied エラーになるのか

もし、MySQL サーバーに接続しようとして Access denied エラーに 遭遇してしまったら、以下に記すことが問題の解決のための指標となるでしょう:

6.13 MySQL をクラッカーに対して安全にする方法

MySQL サーバーに接続するときは、パスワードを使用すべきです。 パスワードはコネクション間で、べたテキストでは流れません。

その他の全ての情報はテキストで転送され、 これは接続を覗くことが出来る人に読まれます。 もしこれを心配するなら、圧縮プロトコル(MySQL 3.22 以上)を 使用することが出来ます。より安全にしたい場合、 ssh (http://www.cs.hut.fi/ssh) をインストールすべきです。 これを使用すれば、MySQL サーバーと MySQL クライアント 間の TCP/IP コネクションは全て暗号化されます。 MySQL システムを安全にするためには、次のことを考えるべきです:

mysqld への次のオプションはセキュリティに影響します:

--secure
gethostbyname() から返される ip がオリジナルのホスト名に戻せるかど うかをチェックします。これは、外の誰かが他のホストを真似てアクセスを得る ことを難しくします。このオプションはいくつかの正しいホスト名チェックも追 加します。これは、時にチェックに長い時間がかかるため、MySQL 3.21 ではデフォルトではオフにされています。MySQL 3.22 ではこのオプションは デフォルトで有効になっていますが、ホスト名をキャッシュするようになっています。
--skip-grant-tables
特権システムを全く使用しません。これは全員に全てのデータベースへの 完全なアクセス を与えます! (mysqladmin reload を実行することで、起動しているサーバーは特権システムを使用するようになります。)
--skip-name-resolve
ホスト名を解析しません。特権テーブル中の全ての Hostフィールドは IP アドレスか localhost でなければなりません。
--skip-networking
ネットワーク (TCP/IP) 経由の接続を許可しません。mysqld への全ての接続は、 Unix ソケットで行われます。MIT-pthreads は Unix ソケットをサポートしない ため、このオプションは MIT-pthreads を使用するシステム上では、うまく動きません。


Go to the first, previous, next, last section, table of contents.