2015年6月9日火曜日

MySQL 5.7.4で導入されたdefault_password_lifetimeがじわじわくる(MySQL 5.7.11でFIX!!)

【2016/01/13 10:12】
MySQL 5.7.11でdefault_password_lifetimeのデフォルトは0に変更になりました!
それ以降のバージョンであればこの記事の内容は気にする必要はありません。

日々の覚書: MySQL 5.7.11でdefault_password_lifetimeのデフォルトが0になるらしい!



TL;DR

default_password_lifetime= 0 を秘伝のmy.cnfに入れておくつもり。



MySQL :: MySQL 5.7 Reference Manual :: 5.1.4 Server System Variables


パラメーターの意味は読んで字のごとく、「最後にパスワードが更新されてからこの期間が経つと、パスワードをEXPIREする」。暗黙のデフォルトは360で、単位は日。つまり何もいじらないと、新規作成したユーザーは360日後にパスワードがEXPIREされてアプリが止まる。。


mysql57> CREATE USER yoku0825 IDENTIFIED WITH mysql_native_password AS '*E74858DB86EBA20BC33D0AECAE8A8108C56B17FA';
Query OK, 0 rows affected (0.03 sec)

mysql57> SELECT user, host, plugin, authentication_string, password_expired, password_last_changed, password_lifetime, account_locked FROM mysql.user WHERE user= 'yoku0825'\G
*************************** 1. row ***************************
                 user: yoku0825
                 host: %
               plugin: mysql_native_password
authentication_string: *E74858DB86EBA20BC33D0AECAE8A8108C56B17FA
     password_expired: N
password_last_changed: 2015-06-09 11:06:33
    password_lifetime: NULL
       account_locked: N
1 row in set (0.00 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
+----------------+
| current_user() |
+----------------+
| yoku0825@%     |
+----------------+

こんなユーザーを作ってみる。360日待ってはいられないので、password_last_changedを過去に戻すことで状況を再現させてみる。


mysql57> UPDATE mysql.user SET password_last_changed= '1999-07-31 00:00:00' WHERE user= 'yoku0825'\G
Query OK, 1 row affected (0.07 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql57> SELECT user, host, plugin, authentication_string, password_expired, password_last_changed, password_lifetime, account_locked FROM mysql.user WHERE user= 'yoku0825'\G
*************************** 1. row ***************************
                 user: yoku0825
                 host: %
               plugin: mysql_native_password
authentication_string: *E74858DB86EBA20BC33D0AECAE8A8108C56B17FA
     password_expired: N
password_last_changed: 1999-07-31 00:00:00
    password_lifetime: NULL
       account_locked: N
1 row in set (0.00 sec)

mysql57> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.04 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
ERROR 1862 (HY000): Your password has expired. To log in you must change it using a client that supports expired passwords.

うむ、これはいい。余計なお世話だけど、これはまだいい。
この時にmysql.userの中身を見てみても、


mysql57> SELECT user, host, plugin, authentication_string, password_expired, password_last_changed, password_lifetime, account_locked FROM mysql.user WHERE user= 'yoku0825'\G
*************************** 1. row ***************************
                 user: yoku0825
                 host: %
               plugin: mysql_native_password
authentication_string: *E74858DB86EBA20BC33D0AECAE8A8108C56B17FA
     password_expired: N
password_last_changed: 1999-07-31 00:00:00
    password_lifetime: NULL
       account_locked: N
1 row in set (0.00 sec)

password_expiredは'N'のままだし、password_filetimeはNULLのままだ。

ということは、


mysql57> SET GLOBAL default_password_lifetime= 36500;
Query OK, 0 rows affected (0.00 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
+----------------+
| current_user() |
+----------------+
| yoku0825@%     |
+----------------+

mysql57> SET GLOBAL default_password_lifetime= 0;
Query OK, 0 rows affected (0.00 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
+----------------+
| current_user() |
+----------------+
| yoku0825@%     |
+----------------+

default_password_lifetimeを大きくしてやればそのまま通るし、default_password_lifetime= 0はデフォルトのライフタイムを無効化する値なのでこちらでも通る。
これ、アカウントの作成時に判定しているのではなくて、ログインのたびに check_password_lifetime関数 の中で判定している。password_lifetimeが設定されていればその値を、NULLならdefault_password_lifetimeを、そして *0なら* 決してEXPIREしない。


mysql57> SELECT @@default_password_lifetime;
+-----------------------------+
| @@default_password_lifetime |
+-----------------------------+
|                         360 |
+-----------------------------+
1 row in set (0.00 sec)

いったんもとに戻して、ALTER USERをいろいろ叩いてみた。
MySQL :: MySQL 5.7 Reference Manual :: 13.7.1.1 ALTER USER Syntax


mysql57> ALTER USER yoku0825 PASSWORD EXPIRE NEVER;
Query OK, 0 rows affected (0.00 sec)

mysql57> SELECT user, host, plugin, authentication_string, password_expired, password_last_changed, password_lifetime, account_locked FROM mysql.user WHERE user= 'yoku0825'\G
*************************** 1. row ***************************
                 user: yoku0825
                 host: %
               plugin: mysql_native_password
authentication_string: *E74858DB86EBA20BC33D0AECAE8A8108C56B17FA
     password_expired: N
password_last_changed: 1999-07-31 00:00:00
    password_lifetime: 0
       account_locked: N
1 row in set (0.00 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
+----------------+
| current_user() |
+----------------+
| yoku0825@%     |
+----------------+

EXPIRE NEVERにすると、password_lifetimeカラムの値が0になる。default_password_lifetimeは評価されない。


mysql57> ALTER USER yoku0825 PASSWORD EXPIRE DEFAULT;
Query OK, 0 rows affected (0.00 sec)

mysql57> SELECT user, host, plugin, authentication_string, password_expired, password_last_changed, password_lifetime, account_locked FROM mysql.user WHERE user= 'yoku0825'\G
*************************** 1. row ***************************
                 user: yoku0825
                 host: %
               plugin: mysql_native_password
authentication_string: *E74858DB86EBA20BC33D0AECAE8A8108C56B17FA
     password_expired: N
password_last_changed: 1999-07-31 00:00:00
    password_lifetime: NULL
       account_locked: N
1 row in set (0.00 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
ERROR 1862 (HY000): Your password has expired. To log in you must change it using a client that supports expired passwords.

EXPIRE DEFAULTにするとpassword_lifetimeがNULLになり、default_password_lifetimeの影響を受ける。


mysql57> ALTER USER yoku0825 PASSWORD EXPIRE INTERVAL 36000 DAY;
Query OK, 0 rows affected (0.00 sec)

mysql57> SELECT user, host, plugin, authentication_string, password_expired, password_last_changed, password_lifetime, account_locked FROM mysql.user WHERE user= 'yoku0825'\G
*************************** 1. row ***************************
                 user: yoku0825
                 host: %
               plugin: mysql_native_password
authentication_string: *E74858DB86EBA20BC33D0AECAE8A8108C56B17FA
     password_expired: N
password_last_changed: 1999-07-31 00:00:00
    password_lifetime: 36000
       account_locked: N
1 row in set (0.00 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
+----------------+
| current_user() |
+----------------+
| yoku0825@%     |
+----------------+

EXPIRE INTERVAL .. DAYでライフタイムを決め打ちすると、そちらが優先される(nullでないのでdafault_password_lifetimeは読まない)


mysql57> ALTER USER yoku0825 PASSWORD EXPIRE;
Query OK, 0 rows affected (0.00 sec)

mysql57> SELECT user, host, plugin, authentication_string, password_expired, password_last_changed, password_lifetime, account_locked FROM mysql.user WHERE user= 'yoku0825'\G
*************************** 1. row ***************************
                 user: yoku0825
                 host: %
               plugin: mysql_native_password
authentication_string: *E74858DB86EBA20BC33D0AECAE8A8108C56B17FA
     password_expired: Y
password_last_changed: 1999-07-31 00:00:00
    password_lifetime: 36000
       account_locked: N
1 row in set (0.00 sec)

$ mysql57 -uyoku0825 -p -e "SELECT current_user()"
Enter password:
ERROR 1862 (HY000): Your password has expired. To log in you must change it using a client that supports expired passwords.

EXPIREだけで他に何もつけない状態だと、password_expiredが'Y'に更新される。この場合、password_last_changedは評価されず(check_password_lifetime関数の中には入るけど、最初のif文ですぐ抜ける)、EXPIRE状態になる。この状態になると、password_expired= 'N'に戻すためにSET PASSWORDで変更するか、UPDATEしてFLUSH PRIVILEGESするしかない。

思いもよらず360日後にこの罠に襲われる人が、1人でも少なくなりますように。


【2015/06/09 18:47】
デフォルトは0にするかワーニングとか出して、ってFeature Requestを上げました。
ダウンロードする時に「No thanks」を知らずにアカウント作っちゃった人とか、"Affects Me"で応援していただけるとありがたいです。

MySQL Bugs: #77277: default_password_lifetime should be set 0 as implicit default value

0 件のコメント :

コメントを投稿