mysqlcharacter-encodingcollationpassword-storage

MySQL Case Sensitivity (or otherwise, how to store passwords correctly in MySQL)


CAUSE:

I have a table and the columns are all suitably Collated as utf8mb4_unicode_ci,

CREATE TABLE IF NOT EXISTS `users` (
  `user_id` int(8) NOT NULL AUTO_INCREMENT,
  `username` varchar(100) NOT NULL,
  `pass_word` varchar(512) NOT NULL ,
  ...etc etc...
  PRIMARY KEY (`user_id`),
  UNIQUE KEY `email_addr` (`email_addr`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=989 ;

...Including the column storing the password hash (generated from password_hash) such as $2y$14$tFpExwd2TXm43Bd20P4nkMbL1XKxwF.VCpL.FXeVRaUO3FFxGJ4Di.

BUT, I find that due to the case insensitivity of the column, that a hash of $2y$14$tFpExwd2tXm43Bd20P4NKmbL1XKxwF.VCpL.FxEVRaUO3FFxGJ4DI would still allow access.

This means that there are potentially hundreds of collisions possible by storing the data in a case insensitive manner. Not good.


ISSUE:

Now, Is there a way of forcing MySQL to treat pass_word column as a case sensitive column, when doing comparisons. I want to avoid having to edit every occurance of the PHP/SQL querying, and instead simply set the database table column to compare in a case sensitive manner by default.

The utf8mb4 character set does not give me any _cs options, and the only non-_ci option appears to be utf8mb4_bin.

So simple questions:

EDIT

As detailed by nj_ , this is a silly issue that is not an issue at all because the value of pass_word is never directly edited when logging in. ... It's been a long day.


Solution

  • If you're really that worried about the potential 2^55 collisions in your 62^55 address space, you can simply change the column type to BLOB, which is always case-sensitive.

    CREATE TABLE IF NOT EXISTS `users` (
      `user_id` int(8) NOT NULL AUTO_INCREMENT,
      `username` varchar(100) NOT NULL,
      `pass_word` BLOB NOT NULL ,
      ...etc etc...
      PRIMARY KEY (`user_id`),
      UNIQUE KEY `email_addr` (`email_addr`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=989 ;
    

    Example:

    INSERT INTO `users` (..., `pass_word`) VALUES (..., 'AbC');

    SELECT * FROM `users` WHERE `pass_word` = 'AbC' LIMIT 0,1000; -> 1 hit

    SELECT * FROM `users` WHERE `pass_word` = 'abc' LIMIT 0,1000; -> 0 hits