2013-11-15 208 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