我对MySQL用户表有一个奇怪的问题。我已经快速创建了一个简化版本作为测试用例。
我有下表
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`identity` varchar(255) NOT NULL,
`credential` varchar(255) NOT NULL,
`credentialSalt` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=ucs2 AUTO_INCREMENT=2 ;
INSERT INTO `users` (`id`, `identity`, `credential`, `credentialSalt`) VALUES
(1, 'test', '7288edd0fc3ffcbe93a0cf06e3568e28521687bc', '123');
我运行以下查询
SELECT id,
IF (credential = SHA1(CONCAT('test', credentialSalt)), 1, 0) AS dynamicSaltMatches,
credentialSalt AS dynamicSalt,
SHA1(CONCAT('test', credentialSalt)) AS dynamicSaltHash,
IF (credential = SHA1(CONCAT('test', 123)), 1, 0) AS staticSaltMatches,
123 AS staticSalt,
SHA1(CONCAT('test', 123)) AS staticSaltHash
FROM users
WHERE identity = 'test'
这给了我以下结果
当静态盐 DOES 匹配时,动态盐 NOT 匹配。
这让我大吃一惊。有人可以帮我指出原因吗?
我的MySQL版本 5.5.29
答案 0 :(得分:4)
这是因为您的表格的默认字符集。您似乎在UTF8数据库上运行此操作,而SHA1()
中的某些内容在使用不同的字符集时出现问题。
如果您将表格声明更改为以下内容,它将再次匹配:
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`identity` varchar(255) NOT NULL,
`credential` varchar(255) NOT NULL,
`credentialSalt` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;
由于robertklep commented明确地将字符串转换为字符也会有效,基本上确保您在使用SHA1()
进行比较时使用相同的字符集
作为the encryption functions documentation says:
许多加密和压缩函数返回结果可能包含任意字节值的字符串。如果要存储这些结果,请使用具有VARBINARY或BLOB二进制字符串数据类型的列。这将避免可能会更改数据值的尾随空格删除或字符集转换的潜在问题,例如,如果使用非二进制字符串数据类型(CHAR,VARCHAR,TEXT),则可能会出现此问题。
从MySQL 5.5.3开始,返回值是连接字符集中的非二进制字符串。在5.5.3之前,返回值是二进制字符串;请参阅本节开头的注释,将值用作非二进制字符串。