0

我正在编写一个快速 REST 服务来管理我们域的电子邮件帐户,并且遇到了我无法解释的奇怪行为。

我正在使用 mysql 对电子邮件帐户进行身份验证,我们的 REST 服务管理邮件目录并使用 Web 界面插入或更新身份验证凭据。插入用户和更新密码的查询都使用encryptmysql 命令。

奇怪的是,在 REST 界面上至少更改一次密码之前,插入的用户将无法进行身份验证。这意味着encrypt为更新设置了正确的值,但为插入设置了错误的值。

我已尝试在其余服务端的 GET/POST 参数中记录所有内容,但似乎数据库层出现了问题。REST 服务在两个端点记录正确的密码参数。执行查询的过程有所不同。

我的查询看起来像这样(在 Python 中使用 MySQLdb):

ADD_USER = "INSERT INTO users (id,name,maildir,crypt) VALUES (%s,%s,%s,encrypt(%s));"

CHANGE_PASS = "UPDATE users SET crypt = encrypt(%s) WHERE id=%s"

再次,ADD_USER输入一个错误的哈希值,CHANGE_PASS成功地使用完全相同的 HTTP 参数crypt传递给它们(作为字符串)。数据层是否有任何理由会进行不同的加密,或者我是在吠叫错误的树吗?

4

2 回答 2

1

如果您使用不加盐的加密,它将根据当前时间使用盐,因此每次调用它时,您都会得到不同的哈希:

mysql> select encrypt('test');
+-----------------+
| encrypt('test') |
+-----------------+
| 92SErC2PadiaQ   |
+-----------------+

mysql> select encrypt('test');
+-----------------+
| encrypt('test') |
+-----------------+
| A2jgxXgOJx7ls   |
+-----------------+

前两个字符(在标准情况下)是盐。如果你想检查它,你使用旧密码作为盐,除了前两个字符之外的所有内容都被忽略:

mysql> select encrypt('test', 'A2jgxXgOJx7ls');
+----------------------------------+
| encrypt('test', 'A2jgxXgOJx7ls') |
+----------------------------------+
| A2jgxXgOJx7ls                    |
+----------------------------------+

如果你想要更强的密码,你必须使用特殊的盐:

mysql> select encrypt('test', '$1$12345678$') as md5;
+------------------------------------+
| md5                                |
+------------------------------------+
| $1$12345678$oEitTZYQtRHfNGmsFvTBA/ |
+------------------------------------+

mysql> select encrypt('test', '$5$0123456789abcdef$') sha256;
+-----------------------------------------------------------------+
| sha256                                                          |
+-----------------------------------------------------------------+
| $5$0123456789abcdef$Wm4jf6bGxEoelzY0H/fTvcw8Qcshq0hyLaRfZWtN8q. |
+-----------------------------------------------------------------+

mysql> select encrypt('test', '$6$0123456789abcdef$') as sha512;
+------------------------------------------------------------------------------------------------------------+
| sha512                                                                                                     |
+------------------------------------------------------------------------------------------------------------+
| $6$0123456789abcdef$vNATSYYTivQfXwPTUT4q.sRFLs/sgxDXaPipzRlX3WOO4r1NcR.Og5OoU2Cd2agm1WA3pCJ30JU4EKMxpZaDy/ |
+------------------------------------------------------------------------------------------------------------+

所以这一切都取决于你使用什么盐。永远不要使用无盐哈希。

于 2012-05-16T17:58:06.053 回答
1

首先:ENCRYPT()如果可以,请不要使用密码。它有点受限(例如:它忽略密码前 8 个字符之外的所有内容),而且它不是特别安全,尤其是因为这意味着 MySQL 查询日志记录将记录您用户的密码!你最好在 Python 中进行密码散列——这意味着 MySQL 不仅不需要知道任何关于实际密码的信息,而且还允许你使用更强大的密码散列算法。

话虽如此,请记住这ENCRYPT()不是一个纯粹的哈希函数。除非您将盐作为第二个参数传递,否则其结果不是恒定的。你如何检查密码?正确的解决方案如下所示:

SELECT * FROM users WHERE <...> AND crypt = ENCRYPT(%s, crypt) ...

或者,在 Python 中:

row.crypt == crypt.crypt(users_input_password, row.crypt)
于 2012-05-16T17:39:12.313 回答