MySQL では、mysql
データベースの user
テーブルにユーザーアカウントがリストされます。各 MySQL アカウントにパスワードを割り当てることができますが、user
テーブルはパスワードの平文バージョンを格納せず、パスワードから計算されたハッシュ値を格納します。
MySQL では、クライアントとサーバーの通信の 2 つのフェーズでパスワードが使用されます。
クライアントがサーバーに接続しようとすると、初期認証ステップがあり、そのステップでは、クライアントが使用するアカウントについての
user
テーブルに格納されたハッシュ値に一致するハッシュ値を持つパスワードをクライアントが提供する必要があります。クライアントが接続したあと、クライアントは (十分な権限がある場合に)
user
テーブルにリストされているアカウントについてのパスワードハッシュを設定または変更することができます。クライアントは、PASSWORD()
関数を使用してパスワードハッシュを生成するか、パスワード生成ステートメント (CREATE USER
、GRANT
、またはSET PASSWORD
) を使用することによって、これを行うことができます。
言い換えると、クライアントが最初に接続しようとしたとき、サーバーは認証中にハッシュ値を検査します。接続されたクライアントが PASSWORD()
関数を呼び出すか、パスワード生成ステートメントを使用してパスワードを設定または変更する場合、サーバーはハッシュ値を生成します。
MySQL のパスワードハッシュ方式には、次に記述するような歴史があります。これらの変更は、パスワードハッシュ値を計算する PASSWORD()
関数からの結果と、パスワードが格納される user
テーブルの構造の変更によって説明されます。
元の (4.1 より前の) ハッシュ方式
元のハッシュ方式では 16 バイト文字列が生成されていました。そのようなハッシュは、次のようになります。
mysql> SELECT PASSWORD('mypass');
+--------------------+
| PASSWORD('mypass') |
+--------------------+
| 6f8c114b58f2ce9e |
+--------------------+
アカウントパスワードを格納するために、user
テーブルの Password
カラムは、この時点で 16 バイト長でした。
4.1 ハッシュ方式
MySQL 4.1 では、セキュリティーを高めてパスワードが傍受されるリスクを低下させる、パスワードハッシュが導入されました。この変更にはさまざまな側面がありました。
PASSWORD()
関数結果の形式の変更Password
カラムの拡張デフォルトのハッシュ方式による制御
サーバーに接続しようとするクライアントについて、許可されたハッシュ方式による制御
MySQL 4.1 の変更は、2 段階で行われました。
MySQL 4.1.0 では 4.1 ハッシュ方式の予備バージョンが使用されていました。この方式は使用期間がたいへん短かったため、以後の説明ではこれについては言及しません。
-
MySQL 4.1.1 ではハッシュ方式が変更され、41 バイトの長いハッシュ値が生成されるようになりました。
mysql> SELECT PASSWORD('mypass'); +-------------------------------------------+ | PASSWORD('mypass') | +-------------------------------------------+ | *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4 | +-------------------------------------------+
長いパスワードハッシュ形式は暗号化特性に優れ、長いハッシュに基づくクライアント認証の方が短いハッシュに基づく認証よりセキュアです。
長いパスワードハッシュに対応するために、
user
テーブルのPassword
カラムはこの時点で現在の長さである 41 バイトに変更されました。拡張された
Password
カラムは、4.1 より前と 4.1 の両方の形式でパスワードハッシュを格納できます。特定のハッシュ値の形式は、2 つの方法で決定されます。長さ: 4.1 および 4.1 より前のハッシュは、それぞれ 41 バイトと 16 バイトです。
4.1 形式のパスワードハッシュは常に 「
*
」 文字で始まりますが、4.1 より前の形式のパスワードでそうなることはありません。
4.1 より前のパスワードハッシュを明示的に生成できるようにするために、2 つの追加変更が行われました。
ハッシュ値を 16 バイト形式で返す
OLD_PASSWORD()
関数が追加されました。互換性目的で、DBA およびアプリケーションがハッシュ方式を制御できるようにする
old_passwords
システム変数が追加されました。old_passwords
値がデフォルトの 0 のときは、ハッシュで 4.1 方式を使用し、(41 バイトのハッシュ値)、old_passwords=1
と設定すると、ハッシュで 4.1 より前の方式を使用します。この場合、PASSWORD()
は 16 バイト値を生成し、OLD_PASSWORD()
と同等です
クライアントが接続できる方法を DBA が制御できるようにするために、
secure_auth
システム変数が追加されました。この変数を無効または有効にしてサーバーを起動することにより、クライアントが 4.1 より前の古いパスワードハッシュ方式を使用して接続することを許可または禁止します。MySQL 5.6.5 より前では、secure_auth
はデフォルトで無効になっています。5.6.5 の時点では、よりセキュアなデフォルト構成を促進するためにsecure_auth
はデフォルトで有効になっています (DBA は自らの裁量によりこれを無効化できますが、これは推奨されません)。4.1 より前のパスワードハッシュは非推奨であるため使用しないようにしてください。(アカウントのアップグレード手順については、セクション6.3.8.3「4.1 よりも前のパスワードハッシュ方式と mysql_old_password プラグインからの移行」を参照してください。)さらに、mysql クライアントは、
secure_auth
に類似した--secure-auth
オプションをサポートしますが、これはクライアント側から指定します。これは 4.1 より前のパスワードハッシュを使用する、セキュアではないアカウントへの接続を防ぐために使用できます。このオプションは、MySQL 5.6.7 より前ではデフォルトで無効になっていますが、それ以降では有効になっています。
ハッシュ方式に関する互換性の問題
MySQL 4.1 での 16 バイトから 41 バイトへの Password
カラムの拡張は、インストールまたはアップグレード操作に次のように影響します。
MySQL の新規インストールを実行する場合、
Password
カラムは自動的に 41 バイトの長さになります。MySQL 4.1 以降から現在のバージョンの MySQL へのアップグレードでは、どちらのバージョンも同じカラム長とパスワードハッシュ方式を使用しているため、
Password
カラムに関して問題は何も発生しないはずです。4.1 より前のリリースから 4.1 以降へのアップグレードの場合、アップグレード後にシステムテーブルをアップグレードする必要があります。(セクション4.4.7「mysql_upgrade — MySQL テーブルのチェックとアップグレード」を参照してください。)
4.1 ハッシュ方式は MySQL 4.1 (およびそれ以降の) サーバーとクライアントによってのみ認識されるため、互換性の問題が発生する可能性があります。4.1 またはそれより新しいクライアントは、4.1 より前と 4.1 のパスワードハッシュ方式の両方を認識するため、4.1 より前のサーバーに接続できます。ただし、4.1 より前のクライアントが 4.1 またはそれより新しいサーバーに接続しようとすると、問題が発生することがあります。たとえば、4.0 の mysql クライアントは次のエラーメッセージを出して失敗することがあります。
shell> mysql -h localhost -u root
Client does not support authentication protocol requested
by server; consider upgrading MySQL client
この現象は、MySQL 4.1 以降にアップグレードしたあとで、古い PHP mysql
拡張を使用しようとしたときにも発生します。(Common Problems with MySQL and PHPを参照してください。)
次の説明では、4.1 より前と 4.1 のハッシュ方式の違いについて、およびサーバーをアップグレードしたが 4.1 より前のクライアントとの下位互換性を保持する必要がある場合にどうすればよいかについて記載します。(ただし、古いクライアントによる接続を維持することは推奨されず、可能な場合は避けるようにしてください。)セクションB.5.2.4「クライアントは認証プロトコルに対応できません」から追加情報を見つけることができます。この情報は、MySQL データベースを 4.1 より古いバージョンから 4.1 以降にマイグレーションを実行する PHP プログラマにとって特に重要です。
短いパスワードハッシュと長いパスワードハッシュの違いは、サーバーが認証中にパスワードを使用する方法と、パスワード変更操作を実行する接続対象のクライアントに対してサーバーがパスワードハッシュを生成する方法の両方に関係します。
サーバーが認証中にパスワードハッシュを使用する方法は、Password
カラムの幅によって影響します。
カラムが短い場合、短いハッシュ認証のみが使用されます。
-
カラムが長い場合、短いハッシュまたは長いハッシュのいずれかを保持でき、サーバーはいずれかの形式を使用できます。
4.1 より前のクライアントは接続できますが、4.1 より前のハッシュ方式のみ認識するため、短いハッシュを持つアカウントを使用してのみ認証できます。
4.1 以降のクライアントは、短いハッシュまたは長いハッシュを持つアカウントを使用して認証できます。
短いハッシュのアカウントであっても、認証プロセスは、古いクライアントよりも 4.1 以降のクライアントの方が実際には少しセキュアです。セキュリティーの観点で、セキュアでないものからもっともセキュアなものの順に並べると、次のようになります。
短いパスワードハッシュで認証する 4.1 より前のクライアント
短いパスワードハッシュで認証する 4.1 以降のクライアント
長いパスワードハッシュで認証する 4.1 以降のクライアント
接続対象のクライアントに対してサーバーがパスワードハッシュを生成する方法は、Password
カラムの幅と、old_passwords
システム変数に影響されます。4.1 以降のサーバーは、特定の条件が満たされた場合にのみ長いハッシュを生成し、この条件とは、Password
カラムが長い値を保持するための十分な幅を持つこと、および old_passwords
が 1 に設定されていてはいけないということです。
これらの条件は次のように適用されます。
Password
カラムは、長いハッシュ (41 バイト) を保持するための十分な幅を持つ必要があります。カラムが更新されておらず、4.1 より前の 16 バイトの幅のままである場合、サーバーは長いハッシュがカラムに適合しないことを認識し、クライアントがPASSWORD()
関数またはパスワード生成ステートメントを使用してパスワード変更操作を実行したときに、サーバーは短いハッシュのみ生成します。これは、4.1 より古い MySQL バージョンから 4.1 以降にアップグレードしたが、Password
カラムを拡張するための mysql_upgrade プログラムをまだ実行していない場合に発生する動作です。Password
カラムが広い場合、短いパスワードハッシュまたは長いパスワードハッシュのいずれかを格納できます。この場合は、代わりに短いパスワードハッシュを生成することをサーバーに強制するためにold_passwords
システム変数を 1 に設定してサーバーが起動されないかぎり、PASSWORD()
関数およびパスワード生成ステートメントは長いハッシュを生成します。
old_passwords
システム変数の目的は、ほかの状況ではサーバーが長いパスワードハッシュを生成するような状況で、4.1 より前のクライアントとの下位互換性を許可することです。このオプションは認証に影響しませんが (4.1 以降のクライアントは、長いパスワードハッシュを持つアカウントを引き続き使用できます)、パスワード変更操作の結果として user
テーブル内で長いパスワードハッシュが作成されないようにします。この発生が許される場合、アカウントは 4.1 より前のクライアントによって使用できなくなります。old_passwords
を無効にすると、次のような好ましくないシナリオが発生する可能性があります。
4.1 より前の古いクライアントが、短いパスワードハッシュを持つアカウントに接続します。
クライアントが自分のパスワードを変更します。
old_passwords
が無効なとき、これによりアカウントは長いパスワードハッシュを持つようになります。古いクライアントがアカウントに次回接続しようとしたとき、古いクライアントは接続できません。これはアカウントが、認証中に 4.1 ハッシュ方式を必要とする長いパスワードハッシュを持つためです。(アカウントがユーザーテーブルに長いパスワードハッシュを持つようになると、4.1 より前のクライアントは長いハッシュを認識しないため、4.1 以降のクライアントのみが認証できます。)
このシナリオでは、4.1 より前の古いクライアントをサポートする必要がある場合、old_passwords
を 1 に設定しないで 4.1 またはそれより新しいサーバーを実行することは問題があるということを示しています。old_passwords=1
を指定してサーバーを実行することにより、パスワード変更操作は長いパスワードハッシュを生成せず、アカウントが古いクライアントからアクセスできなくなることはありません。(これらのクライアントは、自分のパスワードを変更し、長いパスワードハッシュを結局得ることによって誤って自分自身をロックアウトしてしまうことはありません。)
old_passwords=1
の欠点は、4.1 以降のクライアントについても、作成または変更されたすべてのパスワードが短いハッシュを使用することです。つまり、長いパスワードハッシュによって提供される追加のセキュリティーが失われます。長いハッシュ (たとえば 4.1 クライアントによって使用するためのもの) を持つアカウントを作成するか、長いパスワードハッシュを使用するための既存のアカウントを変更するために、管理者は old_passwords
のセッション値を 0 に設定し、グローバル値を 1 に設定したままにすることができます。
mysql> SET @@SESSION.old_passwords = 0;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @@SESSION.old_passwords, @@GLOBAL.old_passwords;
+-------------------------+------------------------+
| @@SESSION.old_passwords | @@GLOBAL.old_passwords |
+-------------------------+------------------------+
| 0 | 1 |
+-------------------------+------------------------+
1 row in set (0.00 sec)
mysql> CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'newpass';
Query OK, 0 rows affected (0.03 sec)
mysql> SET PASSWORD FOR 'existinguser'@'localhost' = PASSWORD('existingpass');
Query OK, 0 rows affected (0.00 sec)
MySQL 4.1 以降では次のシナリオが発生する可能性があります。要因は、Password
カラムが短いか長いかということと、長い場合、サーバーが old_passwords
を有効または無効のいずれに指定して起動したかということです。
シナリオ 1: ユーザーテーブルの Password
カラムが短い場合:
Password
カラムには短いハッシュのみ格納できます。サーバーはクライアント認証中に短いハッシュのみ使用します。
接続対象のクライアントの場合、
PASSWORD()
関数またはパスワード生成ステートメントを含むパスワードハッシュ生成操作では、短いハッシュだけが使用されます。アカウントのパスワードに何らかの変更を行うと、そのアカウントは短いパスワードハッシュを持つことになります。Password
カラムが短いと、サーバーは短いパスワードハッシュのみ生成するため、old_passwords
の値は無関係です。
このシナリオは、4.1 より前の MySQL インストールが 4.1 以降にアップグレードされたが、mysql_upgrade がまだ実行されておらず、mysql
データベース内のシステムテーブルがアップグレードされていない場合に発生します。(これはよりセキュアな 4.1 のパスワードハッシュを使用できなくなるため、推奨される構成ではありません。)
シナリオ 2: Password
カラムが長く、サーバーは old_passwords=1
を指定して起動される場合:
Password
カラムには短いハッシュまたは長いハッシュを格納できます。4.1 以降のクライアントは、短いハッシュまたは長いハッシュを持つアカウントについて認証できます。
4.1 より前のクライアントは、短いハッシュを持つアカウントについてのみ認証できます。
接続対象のクライアントの場合、
PASSWORD()
関数またはパスワード生成ステートメントを含むパスワードハッシュ生成操作では、短いハッシュだけが使用されます。アカウントのパスワードに何らかの変更を行うと、そのアカウントは短いパスワードハッシュを持つことになります。
このシナリオでは、old_passwords=1
によって長いハッシュを生成できないため、新しく作成されるアカウントは短いパスワードハッシュを持ちます。また、old_passwords
を 1 に設定する前に長いハッシュを持つアカウントを作成した場合、old_passwords=1
のときにアカウントのパスワードを変更すると、アカウントには短いパスワードが提供され、長いハッシュの持つセキュリティー上の利点を失うことになります。
長いパスワードハッシュを持つ新しいアカウントを作成するか、長いハッシュを使用するための既存のアカウントを変更するには、以前説明したように、まず old_passwords
のセッション値を 0 に設定し、グローバル値を 1 に設定したままにします。
このシナリオでは、サーバーの Password
カラムは最新状態ですが、サーバーは 4.1 より前のハッシュ値を生成するようにデフォルトのパスワードハッシュ方式を設定して実行されます。これは推奨される構成ではありませんが、4.1 より前のクライアントおよびパスワードが 4.1 以降にアップグレードされる移行期間に役立つことがあります。これが完了したら、old_passwords=0
および secure_auth=1
を指定してサーバーを実行することが推奨されます。
シナリオ 3: Password
カラムが長く、サーバーは old_passwords=0
を指定して起動される場合:
Password
カラムには短いハッシュまたは長いハッシュを格納できます。4.1 以降のクライアントは、短いハッシュまたは長いハッシュを持つアカウントを使用して認証できます。
4.1 より前のクライアントは、短いハッシュを持つアカウントを使用する場合のみ認証できます。
接続対象のクライアントの場合、
PASSWORD()
関数またはパスワード生成ステートメントを含むパスワードハッシュ生成操作では、長いハッシュだけが使用されます。アカウントのパスワードに変更を行うと、そのアカウントは長いパスワードハッシュを持つことになります。
以前示したように、このシナリオの危険性は、短いパスワードハッシュを持つアカウントが 4.1 より前のクライアントからアクセスできなくなることがあるということです。PASSWORD()
関数またはパスワード生成ステートメントを使用して実行したそのようなアカウントのパスワードの変更により、アカウントに長いパスワードハッシュが提供されることになります。その時点以降では、4.1 より前のクライアントはそのアカウントを使用してサーバーに接続できなくなります。クライアントは 4.1 以降にアップグレードする必要があります。
これが問題になる場合、特別な方法でパスワードを変更することができます。たとえば、通常、アカウントのパスワード変更には、SET PASSWORD
を次のように使用しています。
SET PASSWORD FOR 'some_user'@'some_host' = PASSWORD('mypass');
パスワードを変更するが、短いハッシュを作成する場合、代わりに OLD_PASSWORD()
関数を使用します。
SET PASSWORD FOR 'some_user'@'some_host' = OLD_PASSWORD('mypass');
OLD_PASSWORD()
は、短いハッシュを明示的に生成する必要があるような状況で役立ちます。
前の各シナリオの欠点は、次のように要約できます。
シナリオ 1 では、よりセキュアな認証を提供する長いハッシュを活用することができません。
シナリオ 2 では、old_passwords=1
によって、短いパスワードを持つアカウントをアクセス不能にすることはできませんが、注意を払って old_passwords
のセッション値を最初に 0 に変更しないかぎり、パスワード変更操作によって、長いハッシュを持つアカウントは短いハッシュに戻されます。
シナリオ 3 では、短いハッシュを使用するアカウントは OLD_PASSWORD()
を明示的に使用せずにパスワードを変更した場合、4.1 より前のクライアントからアクセスできなくなります。
短いパスワードハッシュに関連する互換性の問題を回避するための最良の方法は、短いパスワードハッシュを使用しない方法です。
すべてのクライアントプログラムを MySQL 4.1 以降にアップグレードする。
old_passwords=0
を指定してサーバーを実行する。長いパスワードハッシュを使用するために、短いパスワードハッシュを持つすべてのアカウントについてのパスワードをリセットする。
セキュリティーを強化するために、
secure_auth=1
を指定してサーバーを実行する。