GA

2024/11/15

アカウント名を間違った時にも java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed が出る

TL;DR

  • caching_sha2_password で作られたアカウントに初回接続する時は useSSL=true または allowPublicKeyRetrieval=trueが必要

  • にもかかわらず、 default_authentication_plugin=mysql_native_password を指定していて、アカウントにも mysql_native_password を指定しているはずなのに Public Key Retrieval is not allowed のエラーが出たら、接続しようとしているアカウントを間違えているだけかもしれない

  • allowPublicKeyRetrieval=trueは悪意を持ったMySQL Serverに接続すると何を食わされるかわからないけど、自分たちが構築したやつならtrue決め打ちでも良いんじゃないか(通信は平文のままなのでオーバーヘッドはほとんどない)


JavaのコードはChatGPTに生成してもらったものをちょっと編集しただけ。ユーザー名、パスワード、useSSL、allowPublicKeyRetrievalを引数に取ってMySQLに接続するだけ。

MySQL Serverは8.0.40, Connector/Jは9.1.0。

MySQLの環境はこう。パスワードはどっちも “a” の1文字なので、引数の2つ目が “a” の時は正しいパスワードで “b” の時は間違ったパスワード。


mysql80 16> SELECT @@default_authentication_plugin;

+---------------------------------+

| @@default_authentication_plugin |

+---------------------------------+

| mysql_native_password           |

+---------------------------------+

1 row in set, 1 warning (0.00 sec)

mysql80 16> SELECT user, host, plugin FROM mysql.user WHERE host <> 'localhost';
+------------------+------+-----------------------+
| user             | host | plugin                |
+------------------+------+-----------------------+
| caching_password | %    | caching_sha2_password |
| native_password  | %    | mysql_native_password |
+------------------+------+-----------------------+
2 rows in set (0.00 sec)

1. mysql_native_passwordの実在するユーザー + 正しいパスワード

当然useSSL, allowPublicKeyRetrievalの値に関わらず接続に成功する。

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password a false false
Connected to the database successfully!

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password a true false
Connected to the database successfully!

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password a false true
Connected to the database successfully!

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password a true true
Connected to the database successfully!

2. mysql_native_passwordの実在するユーザー + 間違ったパスワード

当然全部 Access denied for user ? で失敗する。

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password b false false
java.sql.SQLException: Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password b true false
java.sql.SQLException: Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password b false true
java.sql.SQLException: Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample native_password b true true
java.sql.SQLException: Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

..

3. caching_sha2_passwordの実在するユーザー + 正しいパスワード

useSSL=false, allowPublicKeyRetrieval=falseの場合はエラーになる。
ただし、一度でもログインに成功したらその後はfalse, falseでも成功するようになる。

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password a false false
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password a true false
Connected to the database successfully!

$ mysql80 -e "FLUSH PRIVILEGES"

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password a false true
Connected to the database successfully!

$ mysql80 -e "FLUSH PRIVILEGES"

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password a true true
Connected to the database successfully!

### false, falseでも↑の後にFLUSH PRIVILEGESでキャッシュをリセットしないと結果が違う
$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password a false false
Connected to the database successfully!

caching_sha2_password のキャッシュをリセットして再び Public Key Retrieval is not allowed を出したい場合は FLUSH PRIVILEGES する。

4. caching_sha2_passwordの実在するユーザー + 間違ったパスワード

当然全部転けるが、false, falseの場合のエラーは Public Key Retrieval is not allowed .

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password b false false
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password b true false
java.sql.SQLException: Access denied for user 'caching_password'@'127.0.0.1' (using password: YES)

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password b false true
java.sql.SQLException: Access denied for user 'caching_password'@'127.0.0.1' (using password: YES)

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password b true true
java.sql.SQLException: Access denied for user 'caching_password'@'127.0.0.1' (using password: YES)

..

先に一度正しいパスワードで接続してキャッシュを作ってもエラーは相変わらず

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password a true true
Connected to the database successfully!

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample caching_password b false false
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed

..

5. 存在しないアカウントを指定する

存在しないアカウントを指定すると default_authentication_plugin の値に関わらず caching_sha2_password でパスワードを間違った時と同じ組み合わせでエラーになるぽい。

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample invalid_user a false false
java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample invalid_user a true false
java.sql.SQLException: Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample invalid_user a false true
java.sql.SQLException: Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

..

$ java -cp .:/usr/share/java/mysql-connector-java.jar MySQLConnectionExample invalid_user a true true
java.sql.SQLException: Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

..

おまけにmysqlコマンドラインクライアント。バージョンは8.4.2。
すぐquitしてるからエラーが出なければ接続に成功して終わってる。Warningは無視する。
存在しないアカウントを指定した時の動作がConnector/Jとは違う。

$ mysql -h127.0.0.1 -P64080 -unative_password -pa --ssl-mode=DISABLED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.

$ mysql -h127.0.0.1 -P64080 -unative_password -pa --ssl-mode=REQUIRED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.

$ mysql -h127.0.0.1 -P64080 -unative_password -pa --ssl-mode=DISABLED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.

$ mysql -h127.0.0.1 -P64080 -unative_password -pa --ssl-mode=REQUIRED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.

$ mysql80 -e "FLUSH PRIVILEGES"

$ mysql -h127.0.0.1 -P64080 -unative_password -pb --ssl-mode=DISABLED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

$ mysql -h127.0.0.1 -P64080 -unative_password -pb --ssl-mode=REQUIRED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

$ mysql -h127.0.0.1 -P64080 -unative_password -pb --ssl-mode=DISABLED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

$ mysql -h127.0.0.1 -P64080 -unative_password -pb --ssl-mode=REQUIRED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'native_password'@'127.0.0.1' (using password: YES)

$ mysql -h127.0.0.1 -P64080 -ucaching_password -pa --ssl-mode=DISABLED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2061 (HY000): Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.

$ mysql -h127.0.0.1 -P64080 -ucaching_password -pa --ssl-mode=REQUIRED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.

$ mysql80 -e "FLUSH PRIVILEGES"

$ mysql -h127.0.0.1 -P64080 -ucaching_password -pa --ssl-mode=DISABLED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.

$ mysql80 -e "FLUSH PRIVILEGES"

$ mysql -h127.0.0.1 -P64080 -ucaching_password -pa --ssl-mode=REQUIRED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.

$ mysql80 -e "FLUSH PRIVILEGES"

$ mysql -h127.0.0.1 -P64080 -uinvalid_user -pa --ssl-mode=DISABLED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

$ mysql -h127.0.0.1 -P64080 -uinvalid_user -pa --ssl-mode=REQUIRED --skip-get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

$ mysql -h127.0.0.1 -P64080 -uinvalid_user -pa --ssl-mode=DISABLED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

$ mysql -h127.0.0.1 -P64080 -uinvalid_user -pa --ssl-mode=REQUIRED --get-server-public-key -e quit
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

これ、なんか CHANGE REPLICATION SOURCE TO でもアカウント間違った時に Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection. って怒られた気がするんだけど気のせいだったかな…(再現方法がわかっていない…)


【2024/11/15 19:00】

余談。MySQLのエラーログにはこんな風に出る。

2024-11-15T18:26:29.999904+09:00 25 [Note] [MY-010914] [Server] Got an error reading communication packets         <-- 間違ったパスワードで Public Key Retrieval is not allowed 

2024-11-15T18:26:45.095375+09:00 26 [Note] [MY-010926] [Server] Access denied for user 'caching_password'@'127.0.0.1' (using password: YES)

2024-11-15T18:26:58.924712+09:00 27 [Note] [MY-010926] [Server] Access denied for user 'caching_password'@'127.0.0.1' (using password: YES)

2024-11-15T18:27:14.245506+09:00 28 [Note] [MY-010926] [Server] Access denied for user 'caching_password'@'127.0.0.1' (using password: YES)

..

2024-11-15T18:34:32.642543+09:00 39 [Warning] [MY-013360] [Server] Plugin sha256_password reported: ''sha256_password' is deprecated and will be removed in a future release. Please use caching_sha2_password instead'
2024-11-15T18:34:32.652304+09:00 39 [Note] [MY-010914] [Server] Got an error reading communication packets

## ↑ 存在しないアカウントで Public Key Retrieval is not allowed 

2024-11-15T18:34:46.348753+09:00 40 [Warning] [MY-013360] [Server] Plugin sha256_password reported: ''sha256_password' is deprecated and will be removed in a future release. Please use caching_sha2_password instead'
2024-11-15T18:34:46.350837+09:00 40 [Note] [MY-010926] [Server] Access denied for user 'invalid_user'@'127.0.0.1' (using password: YES)

## ↑存在しないアカウントでAcces denied


存在しないアカウントを指定した時はConnector/J側で他のプラグインもネゴシエーションしようとしているぽい。