MySQL は、mysql.user テーブルにユーザー情報を持っていて、その中に、パスワードを なんらかの手順で ハッシュ化した値を保存している。
何らかの手順 は、プラグイン方式なっていて「認証プラグイン名」として認識されている。
- mysql_native_password → MySQL 5.7 までのデフォルトの認証プラグイン
- caching_sha2_password → MySQL 8.0 のデフォルトの認証プラグイン
MySQL 8.0 でデフォルトの認証プラグインを mysql_native_password に変更したい場合は、 my.cnf で指定する。
[mysqld]
default_authentication_plugin=mysql_native_password
デフォルトの認証プラグインを変更する方法は mysql 5.7 までと同じだが、今までは、この設定をすることはあまりなかったのでは。 当面は、古い(caching_sha2_password を理解しない)データーベースドライバーを使用するために、上記の設定をする場面が多くなるものと思われる。
デフォルトの認証プラグインを my.cnf に指定しなくても mysql_native_password を指定してユーザーを作成することができる。
mysql> CREATE USER native@localhost IDENTIFIED WITH mysql_native_password BY 'secret';
Query OK, 0 rows affected (0.02 sec)
もしくは、既存のユーザーのパスワードと認証方法を変更することもできる。
mysql> ALTER USER native@localhost IDENTIFIED WITH mysql_native_password BY 'secret';
Query OK, 0 rows affected (0.02 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.01 sec)
こうして、 mysql_native_password のユーザーを作成すれば、5.7 までしか対応していないデーターベースドライバーでも接続できるかも(ドライバーによるかも)。
mysql データーベースの参照権限があれば、ユーザー毎にどの認証プラグインを使っているかと、ハッシュ化された値がわかる。
mysql> select user, plugin, authentication_string from mysql.user;
+------------------+-----------------------+------------------------------------------------------------------------+
| user | plugin | authentication_string |
+------------------+-----------------------+------------------------------------------------------------------------+
| mysql.infoschema | mysql_native_password | \*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.session | mysql_native_password | \*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| mysql.sys | mysql_native_password | \*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE |
| native | mysql_native_password | \*14E65567ABDB5135D0CFD9A70B3032C179A49EE7 |
| root | caching_sha2_password | $A$005$icD>\.?y5Z&G9KMf3f6q/v9ivxbgSjgPnZXCCc.l2K3X2UxM10HaXtfSuPX9 |
+------------------+-----------------------+------------------------------------------------------------------------+
5 rows in set (0.00 sec)
上記の例では、 mysql.infoschema, mysql.session, mysql.sys の authentication_string はハッシュ値として正しくないのでログインできるアカウントではない。
認証プラグインは沢山あるが、myql_native_password, caching_sha2_password あたりを考慮しておけばよい それぞれの認証プラグインによるパスワード設定例(再掲)
ALTER USER 'mariaex_user'@'%' IDENTIFIED WITH mysql_native_password BY 'mariaex_pass';
FLUSH PRIVILEGES;
ALTER USER 'mariaex_user'@'%' IDENTIFIED WITH caching_sha2_password BY 'mariaex_pass';
FLUSH PRIVILEGES;
MySQL 4.1 ~ 5.7 のデフォルトの認証プラグイン
- データーベースに保存されているデータ SHA1( SHA1( password ) )
- クライアントから送られるデータ SHA1( password ) XOR SHA1( "20-bytes random data from server" <concat> SHA1( SHA1( password ) ) )
サーバーでは、authentication_string のハッシュ値と random からハッシュ値を作成し、クライアントから送られてくるデータと一致するかチェックする。
MySQL 8.0 のデフォルトの認証プラグイン
https://dev.mysql.com/doc/dev/mysql-server/latest/page_caching_sha2_authentication_exchanges.html
- Fast authentication でクライアントからハッシュ値が送られる XOR(SHA256(password), SHA256(SHA256(SHA256(password)), Nonce))
- Nonce は MySQL の起動の度に変わる揮発性のランダムデータ
- MySQL が起動してからログインに成功していれば、メモリにハッシュ値が残っていて一致しているかチェックできるので Fast authentication で終わり
- MySQL が起動してから一度もログインに成功していなければ、Full authentication のシーケンスが続く
- Full authentication では、上記に加え平文のパスワードをクライアントからサーバーに送る
平文のパスワードは下記のように第三者に覗き見られずにサーバーでデコードできるようにする
- tls や unix domain socket ならそのまま送る
- tcp socket なら Nonce で XOR した値を、サーバーの RSA 公開鍵で暗号化して送る
MySQL サーバーが起動してから一度は Full authentication がおこなわれ、平文のパスワードとデーターベースに保存されているデータからハッシュ値を計算してメモリに保存する。 ハッシュ値をメモリにキャッシュすることにより、認証の強度を保ちつつ性能を上げるようにしている。
パスワードを平文で保存する。 AWS で RDS と IAM認証する場合などに使うらしい。
- CyMySQL(Python) https://github.com/nakagami/CyMySQL
- go-sql-driver(Go) go-sql-driver/mysql#794
- xerios/mariaex xerions/mariaex#236