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
。
这么简单的问题:
MySQL 上的 UTF8mb4_bin
字符集和排序规则是否区分大小写处理标准比较? [是]
UTF8mb4_bin
适合我想做的事情。我应该使用另一套吗?如果是,为什么?
- 在 MySQL
utf8mb4_bin
列中存储 password_hash
输出有任何问题吗?
- 这种方法是否方便地避免了编辑每个登录查询的查询 SQL 的需要?我可以更改列类型然后继续吗?
编辑
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);
原因:
我有一个 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
。
这么简单的问题:
MySQL 上的[是]UTF8mb4_bin
字符集和排序规则是否区分大小写处理标准比较?UTF8mb4_bin
适合我想做的事情。我应该使用另一套吗?如果是,为什么?- 在 MySQL
utf8mb4_bin
列中存储password_hash
输出有任何问题吗? - 这种方法是否方便地避免了编辑每个登录查询的查询 SQL 的需要?我可以更改列类型然后继续吗?
编辑
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);