MySQL 区分大小写(或者,如何在 MySQL 中正确存储密码)

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

原因:

我有一个 table 并且所有列都适合 Collated 作为 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 ;

...包括存储密码散列(从password_hash生成)的列,例如y$tFpExwd2TXm43Bd20P4nkMbL1XKxwF.VCpL.FXeVRaUO3FFxGJ4Di

BUT,我发现由于列的大小写不敏感,y$tFpExwd2tXm43Bd20P4NKmbL1XKxwF.VCpL.FxEVRaUO3FFxGJ4DI 的散列仍然会允许访问。

这意味着以不区分大小写的方式存储数据可能会发生数百次冲突。不好。


问题:

现在,有没有办法在进行比较时强制 MySQL 将 pass_word 列视为 区分大小写的 列。我想避免必须编辑 PHP/SQL 查询的每一次出现,而是简单地将数据库 table 列设置为以区分大小写的方式进行比较 默认情况下

utf8mb4 字符集没有给我任何 _cs 选项,唯一的非 _ci 选项似乎是 utf8mb4_bin

这么简单的问题:

编辑

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.

如果您真的很担心 62^55 地址中可能存在的 2^55 冲突 space,您只需将列类型更改为 BLOB,它始终区分大小写。

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 ;

示例:

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

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

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

在这种情况下区分大小写没有问题,因为无论如何您都无法直接使用SQL 验证密码。无法在数据库中搜索正确加盐的密码哈希。仅按用户名搜索并从数据库中提取存储的哈希值:

$sql= 'SELECT * FROM users WHERE username = ?';
$db->prepare($sql);
$db->bind_param('s', $_POST['username']);

之后,您可以从行中提取哈希值,并使用 password_verify() 函数将输入的密码与找到的哈希值进行比较:

// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from $existingHashFromDb.
$isPasswordCorrect = password_verify($password, $existingHashFromDb);