mita2 database life

主にMySQLに関するメモです

MySQL 8.0 Authentication requires secure connection エラーの件

MySQL 8.0 から デフォルトのパスワードの仕組みが caching_sha2_password に変更されました。 これに関連して、yoku0825 さんが以下のエントリーを掲載してます。

yoku0825.blogspot.com

yokuさんのエントリーを抜粋すると:

  • caching_sha2_password プラグインを使っているアカウント
  • まだサーバー側にSHA2キャッシュが作られていないアカウント
  • サーバーの公開鍵を指定していない非SSLTCP接続

この条件にすべて合致しているとログインが転けて↑のエラーを食らう。

試します

挙動をおさらいします。

サーバ側で FLUSH PRIVILEGES を実行しSHA2キャッシュをクリアしたあと、SSL無効化して接続します。 確かに、Authentication requires secure connection. とエラーが出て、接続できません。

$ mysql -uuser -h my8.local --ssl-mode=DISABLED
ERROR 2061 (HY000): Authentication plugin 'caching_sha2_password' reported error: Authentication requires secure connection.

次に、--get-server-public-key をつけます。このオプションはサーバの公開鍵を自動でクライアントに持ってくるオプションです。 サーバの公開鍵を使って、パスワードを暗号化し、サーバへ送信し、認証が行われます。

$ mysql -uuser -h my8.local --ssl-mode=DISABLED --get-server-public-key
mysql>

一度、接続すれば、SHA2キャッシュが作られるので、以降は--get-server-public-key を指定しなくても接続できるようになります。

$ mysql -uuser -h my8.local --ssl-mode=DISABLED
mysql>

運用への影響を考えてみる

(サーバを再起動したりして) SHA2キャッシュがクリアされたときに、SSLを利用していないクライアントが一斉に接続エラーになっては困ります。 そのようなことが起こり得るか検討してみます。

mysql コマンド

mysql コマンドはデフォルトでSSLを利用します。あえてSSLを無効化しているようなケースはあまりないでしょう。 コマンドラインMySQLを使っている場合は、心配しなくて良さそうです。

各種、言語ドライバーはどうでしょうか? mysql コマンドの --get-server-public-key 相当の挙動がドライバ側に実装されていれば、開発者側では特に意識する必要はないということになりますが。。。

ドライバの挙動

PHP 7.4

PHP 7.4 で試します。

<?php
try {
  $pdo = new PDO('mysql:host=my8.local;charset=utf8','user','Password%123');
} catch (PDOException $e) {
  exit($e->getMessage());
}

$stmt = $pdo->query("SHOW STATUS LIKE 'Ssl_cipher'");
print_r($stmt->fetch(PDO::FETCH_ASSOC));

おっ、特にエラーなく接続できた!Ssl_cipherが空なのでSSL無効でエラーなく接続できました。

$ php pdo.php
Array
(
    [Variable_name] => Ssl_cipher
    [Value] =>
)

PHP の コミットログをみると、きちんとサーバ側の公開鍵を自動で取ってくる実装が追加されていそうです👏

https://github.com/php/php-src/commit/d6e81f0bfd0cb90586dd83d4fd47a4302605261a

PHP7.3

PHP 7.3 でも試します。

$ php pdo.php
SQLSTATE[HY000] [2054] The server requested authentication method unknown to the client

そもそも、caching_sha2_password がサポートされてないようですね 😢 MySQL 8 を使うには PHP7.4 以降を利用する必要があることがわかりました。

node.js

var mysql = require('mysql');

var con = mysql.createConnection({
  host: "my8.local",
  user: "user",
  password: "Password%123"
});

con.connect(function(err) {
  if (err) throw err;
  console.log("Connected!");
});

// simple query
con.query(
  "SHOW STATUS LIKE 'Ssl_cipher'",
  function(err, results, fields) {
    console.log(results);
  }
);

node.js の mysql もまだ caching_sha2_password をサポートしてないようですね。。。。

$ node mysql.js
/home/mita2/nodejs-conn/node_modules/mysql/lib/protocol/Parser.js:437
      throw err; // Rethrow non-MySQL errors
      ^
Error: ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client

PRは出ているのですが、まだ、取り込まれてないようです。 https://github.com/mysqljs/mysql/pull/2233

mysql2 のほうには取り込まれているようなので、mysql2 を試します。 mysqlmysql2 は互換性があります。ドライバを差し替えるにはvar mysql = require('mysql');var mysql = require('mysql2'); にするだけです。

$ node mysql.js
Connected!
[ TextRow { Variable_name: 'Ssl_cipher', Value: '' } ]

大丈夫そうです😄

まとめ

  • PHPは 7.4 以上なら大丈夫!
  • Node.js のドライバは mysql2 なら大丈夫!