简体   繁体   English

在INSERT和UPDATE上,mysql加密的行为是否有所不同?

[英]Does mysql encrypt behave differently on INSERT vs UPDATE?

I am working on writing a quick REST service to manage email accounts for our domain and have ran into a strange behavior I can't explain. 我正在编写一个快速的REST服务来管理我们域的电子邮件帐户,并遇到了一个我无法解释的奇怪行为。

I am using mysql to authenticate email accounts, and our REST service manages the maildirs and inserts or updates auth credentials using a web interface. 我使用mysql来验证电子邮件帐户,我们的REST服务使用Web界面管理maildirs并插入或更新auth凭证。 The queries for inserting users as well as updating their passwords both use the encrypt mysql command. 插入用户以及更新密码的查询都使用encrypt mysql命令。

What is strange is that inserted users won't work for authentication until the password is changed on the REST interface at least once. 奇怪的是,在REST接口上更改密码至少一次之前,插入的用户将无法进行身份验证。 This means that encrypt is setting the right value for an update, but something wrong for an insert. 这意味着encrypt正在为更新设置正确的值,但插入有问题。

I have tried logging everything in the GET/POST params on the rest service side and it seems like something is going wrong in the database tier. 我已经尝试在休息服务端的GET / POST参数中记录所有内容,看起来数据库层出现了问题。 The REST service logs correct params for passwords at both endpts. REST服务在两个端口记录密码的params。 Something in the execution of the queries is different. 执行查询时的某些内容是不同的。

My queries look like such (using MySQLdb in Python): 我的查询看起来像这样(在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"

Again, ADD_USER is entering a bad hash where CHANGE_PASS succeeds with the exact same HTTP parameters for crypt passed into them (as strings). 同样, ADD_USER正在输入一个错误的哈希值,其中CHANGE_PASS成功,并且传递给它们的crypt (作为字符串)具有完全相同的HTTP参数。 Is there any reason why the data tier would do different encryption, or am I barking up the wrong tree? 有没有理由为什么数据层会进行不同的加密,或者我咆哮错误的树?

First of all: Don't use ENCRYPT() for passwords if you can help it. 首先:如果您可以提供帮助,请不要使用ENCRYPT()作为密码。 It's kind of limited (for instance: it ignores everything beyond the first 8 characters of a password), and it's not particularly secure, especially because it means that MySQL query logging will log your users' passwords! 它有点受限(例如:它忽略了密码的前8个字符以外的所有内容),并且它不是特别安全,特别是因为它意味着MySQL查询日志记录将记录用户的密码! You'd do much better to do password hashing in Python -- this means not only that MySQL doesn't have to know anything about the actual passwords, but also allows you to use stronger password hashing algorithms. 你可以更好地在Python中进行密码散列 - 这意味着不仅MySQL不必知道任何有关实际密码的信息,而且还允许你使用更强大的密码散列算法。

That all being said, keep in mind that ENCRYPT() is not a pure hash function. 尽管如此,请记住, ENCRYPT()不是纯哈希函数。 Its results are not constant unless you pass in a salt as the second argument. 除非你传入salt作为第二个参数,否则它的结果不是常数。 How are you checking passwords? 你是如何检查密码的? A correct solution would look something like: 一个正确的解决方案看起来像:

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

Or, in Python: 或者,在Python中:

row.crypt == crypt.crypt(users_input_password, row.crypt)

if you use encrypt without salt, it will use a salt based on the current time, so each time you call it, you'll get a different hash: 如果你使用不带盐的加密,它将使用基于当前时间的盐,所以每次你调用它,你会得到一个不同的哈希:

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

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

the first two characters (in the standard case) are the salt. 前两个字符(在标准情况下)是盐。 if you want to check it, you use the old password as salt, everything but the first two character is ignored: 如果你想检查它,你使用旧密码作为salt,除了前两个字符之外的所有字符都被忽略:

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

if you want stronger passwords, you havet to use a special salt: 如果你想要更强的密码,你必须使用特殊的盐:

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/ |
+------------------------------------------------------------------------------------------------------------+

so it all depends on what salt you use. 所以这一切都取决于你使用的盐。 never use unsalted hashes. 永远不要使用无盐的哈希。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM