Beware: MySQL 5.6.6's ALTER TABLE ... PASSWORD EXPIRE today for a free data buffet!

The MySQL 5.6.6 binaries were released today so I decided to take a look at the changelog. I was looking through some of the interesting-sounding new password and security features when I saw this sentence:

The mysql.user table now has a password_expired column. Its default value is 'N', but can be set to 'Y' with the new ALTER USER statement (which also sets the Password column to the empty string).

That didn't sound right. Why would causing a user's password to expire set their existing password to an empty string? There are two ways I can see this feature working. One is that the user logs in using their old/expired password and is forced to set a new password before they can do anything. The second is that they not be allowed to log in at all, using any password. Unfortunately, a third path is taken in MySQL 5.6.6 where a user can log in with no password at all when their password is expired. Huh?!

This is super easy to reproduce.

Here's my totally normal user called "mysql":

mysql 5.6.6-m9 (root) [test]> select user,host,password,password_expired from mysql.user where user='mysql';
+-------+-----------+-------------------------------------------+------------------+
| user  | host      | password                                  | password_expired |
+-------+-----------+-------------------------------------------+------------------+
| mysql | localhost | *0D3CED9BEC10A777AEC23CCC353A8C08A633045E | N                |
+-------+-----------+-------------------------------------------+------------------+
1 row in set (0.00 sec)

He can log in totally normally:

$ ./bin/mysql -u mysql -pabc -e 'select current_user()'
Warning: Using a password on the command line interface can be insecure.
+-----------------+
| current_user()  |
+-----------------+
| mysql@localhost |
+-----------------+

And then I can expire his password:

mysql 5.6.6-m9 (root) [test]> alter user 'mysql'@'localhost' password expire;
Query OK, 0 rows affected (0.00 sec)

mysql 5.6.6-m9 (root) [test]> select user,host,password,password_expired from mysql.user where user='mysql';
+-------+-----------+----------+------------------+
| user  | host      | password | password_expired |
+-------+-----------+----------+------------------+
| mysql | localhost |          | Y                |
+-------+-----------+----------+------------------+
1 row in set (0.00 sec)

He can still log in using his old password, for the time being, as apparently ALTER USER doesn't cause the privilege tables to be flushed...

$ ./bin/mysql -u mysql -pabc -e 'select current_user()'
Warning: Using a password on the command line interface can be insecure.
ERROR 1820 (HY000) at line 1: You must SET PASSWORD before executing this statement

So far things look pretty reasonable. Expiring the user's password causes his next login attempt to result in him being forced to change his password. Great, looks like reasonable behavior. Except, as I said, it looked like ALTER USER didn't cause the privilege tables to be flushed, as the old password still worked...

mysql 5.6.6-m9 (root) [test]> flush privileges;
Query OK, 0 rows affected (0.01 sec)
kolbe@74-61-10-68 mysql-5.6.6-m9-osx10.7-x86_64 $ ./bin/mysql -u mysql -e 'select current_user()'
ERROR 1820 (HY000) at line 1: You must SET PASSWORD before executing this statement
kolbe@74-61-10-68 mysql-5.6.6-m9-osx10.7-x86_64 $ ./bin/mysql -u mysql -e 'set password=password("uh oh...")'
kolbe@74-61-10-68 mysql-5.6.6-m9-osx10.7-x86_64 $ ./bin/mysql -u mysql -p"uh oh..." -e 'select * from production.all_your_data'
Warning: Using a password on the command line interface can be insecure.
ERROR 1146 (42S02) at line 1: Table 'production.all_your_data' doesn't exist
mysql 5.6.6-m9 (root) [test]> select user,host,password,password_expired from mysql.user where user='mysql';
+-------+-----------+-------------------------------------------+------------------+
| user  | host      | password                                  | password_expired |
+-------+-----------+-------------------------------------------+------------------+
| mysql | localhost | *68877531D6DF73C1A23D45AE3968638FFE15EB91 | N                |
+-------+-----------+-------------------------------------------+------------------+
1 row in set (0.00 sec)

So... if a user's password expires and privileges are flushed or the server is restarted, the user is allowed to connect without any password at all, then change the password to whatever they want, and obviously perform any work that the privileges for that user allow.

The behavior of setting the user's password to an empty string is completely documented at http://dev.mysql.com/doc/refman/5.6/en/alter-user.html so this is not even strictly a bug. Nevertheless, I filed a bug report (http://bugs.mysql.com/bug.php?id=66250); I marked it as a security bug so it is entirely hidden from public view, however. I fully expect that Oracle will change the behavior of this feature very, very soon. The reasonable thing to do would be to leave the Password column untouched, but set the password_expired column so that the user is forced to change his or her password on the next connection.

Even when they do change the behavior of ALTER USER ... PASSWORD EXPIRE, though, I'm not sure what the point of this feature really is. There is no column in mysql.user to indicate when a user last changed his or her password, much less to specify an expiration date, so it's not really possible to create an event or cronjob that would handle automatic password expiration. In its current form, aside from being a hideous and monumental security problem, this feature doesn't make any sense and isn't fully-baked enough to be useful, in my opinion.

Nobody should be using MySQL 5.6 in production at this stage, but even fewer people should be using its ALTER USER ... PASSWORD EXPIRE feature.

Comments

This was a bug that has already been resolved

This turned out to be a bug, and has already been fixed in the 5.6.7 release: http://www.markleith.co.uk/2012/08/08/alter-user-password-expire-bitten-...

Kolbe, changed for the next

Kolbe, changed for the next build, not something we could leave unset for a non-preview release.

 

Thanks for highlighting it!

 

As well as for DBAs forcing people to change passwords we could do things like shipping default accounts with the expire flag set, though nothing to announce yet about how we're handling those.

 

One thing that we're trying to do is increase the security of the server in 5.6 and provide more tools to improve people's options in the security area. It's been unfortunate for some time now that people often leave things insecure and we want to make it easier for people who don't know the server well to get it right, with settings, options and instructions to help them.

 

If you have any thoughts on what we might do along those lines they would be welcome, as would thoughts from others.

 

Views are my own, not necessarily those of Oracle. For an official view consult a PR person.

 

James Day, MySQL Senior Principal Support Engineer, Oracle

Mysql user Groups

The other long missing feature of MySQL has been creating named permissions groups

IE: dba_users
These users have admin rights

report_users
These users only have select privs.

This is extremely useful in large enterprises where several people have direct Mysql Access