2013-11-15 50 views
2

我有一个奇怪的MySQL用户表问题。我很快创建了一个简化版本作为测试用例。MySQL 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=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' 

这给了我下面的结果

enter image description here

动态盐确实NOT匹配,而静态盐匹配

这是在吹我的脑海。有人能帮我指出这个原因吗?

我的MySQL版本是5.5.29

回答

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 ; 

SQL Fiddle

由于robertklep commented明确铸造你的字符串的字符也将正常工作,基本确保您使用的用做比较时相同的字符集SHA1()

由于the encryption functions documentation says

许多加密和压缩函数返回的结果可能包含任意字节值的字符串。如果要存储这些结果,请使用具有VARBINARY或BLOB二进制字符串数据类型的列。这将避免可能会改变数据值的尾随空间移除或字符集转换的潜在问题,例如在使用非二进制字符串数据类型(CHAR,VARCHAR,TEXT)时可能发生的问题。

这是changed in version 5.5.3

在MySQL 5.5.3中,返回值是在连接字符集中的非二进制字符串。在5.5.3之前,返回值是一个二进制字符串;请参阅本节开头的注释,将该值用作非二进制字符串。

+1

明确的转换也似乎解决了这个问题:'SHA1(CONCAT('test',CAST(credentialSalt AS CHAR))'' – robertklep

+0

是的,谢谢@robertklep;如果你不介意的话,我已经半盗取了你的评论。 – Ben

+0

没有,谢谢你的详尽答案:) – robertklep