【问题标题】:OLD_PASSWORD Function in 5.7.5+OLD_PASSWORD 5.7.5+ 中的函数
【发布时间】:2016-10-02 11:05:03
【问题描述】:

我在这里使用一个遗留代码库,目前使用OLD_PASSWORD() 作为一个简单的散列函数。此代码库现在需要连接到运行最新版本 MySQL 5.7 的数据库。

PASSWORD() 的等价物似乎是:UPPER(SHA1(UNHEX(SHA1(password))))

是否有与OLD_PASSWORD()类似的等价物?

【问题讨论】:

  • 使用OLD_PASSWORD() 进行用户身份验证是一个糟糕的主意,因此如果您可以将其替换为真正安全的东西,您的状态会好得多。 OLD_PASSWORD() 只是未加盐的 MD5 吗?你可以做测试来找出答案。如果是的话,就保护而言完全没有用。
  • 我很清楚它不安全。正如我所说,这是一个遗留代码库。目前我无法控制改变。 OLD_PASSWORD() 似乎返回了一个减半的 MD5 字符串(16 个字符),但实际上并非如此。
  • 我找到了A python implementation of the old MySQL PASSWORD() function。我不会说一个 Python 单词,但算法看起来很荒谬。
  • 强制人们每 20 年更新一次密码并不一定是个坏主意。
  • @DanFromGermany 是的,它从 5.7.5 版开始被删除。如果 Google Cloud SQL 提供 MariaDB,我们肯定会选择它。

标签: mysql mysql-5.7


【解决方案1】:

似乎没有等效于OLD_PASSWORD() 使用 MySQL 函数,除非服务器允许设置全局变量。通过执行查询SET @@global.old_passwords = 1;,作为具有超级权限的用户,PASSWORD() 函数然后使用OLD_PASSWORD() 算法对密码进行哈希处理。

如果像我们上面的例子一样,您没有超级用户(Google CloudSQL 不支持它们),则需要替换算法。以下是不同语言的替换:

C | Perl | PHP | Python | SQL

免责声明:MySQL 的旧密码函数are a joke 在现代安全中,应尽可能使用;这些算法一团糟。

【讨论】:

  • 接管旧系统后,最近升级了没有修复密码,实际系统用户使用PASSWORD()函数进行哈希处理,我发现这些脚本很有帮助。我现在已经设法将它们集成到我的升级方法中,并且在使用 PASSWORD() 成功进行身份验证后更新到新的 SHA1
【解决方案2】:

我尝试直接在 SQL 中为 OLD_PASSWORD 编写替换用户定义的函数,它似乎正在工作。代码是本文中 PHP 版本的翻译。

DROP FUNCTION IF EXISTS OLD_PASSWORD;
DELIMITER $$
CREATE FUNCTION OLD_PASSWORD (input BLOB) 
RETURNS CHAR(16)
DETERMINISTIC
BEGIN 
  DECLARE nr BIGINT;
  DECLARE nr2 BIGINT;
  DECLARE ad BIGINT;
  DECLARE inlen INT;
  DECLARE i INT;
  DECLARE b CHAR;
  DECLARE tmp INT;
  DECLARE output CHAR(16);
  
  SET nr = 1345345333;
  SET nr2 = 0x12345671;
  SET ad = 7;
  SET inlen = LENGTH(input);
  SET i = 1;

  IF (input = '' OR input IS NULL) THEN
    RETURN input;
  END IF;

  
  WHILE i <= inlen DO
    SET b = MID(input, i, 1);
    IF b != ' ' AND b != '\t' THEN
      SET tmp = ORD(b);
      SET nr = nr ^ ((((nr & 63) + ad) * tmp) + ((nr << 8) & 0xFFFFFFFF));
      SET nr2 = nr2 + (((nr2 << 8) & 0xFFFFFFFF) ^ nr);
      SET ad = ad + tmp;
    END IF;
    SET i = i + 1;
  END WHILE;
    
  SET nr  = nr  & ((1 << 31) - 1);
  SET nr2 = nr2 & ((1 << 31) - 1);      
  SET output = LOWER(CONCAT(LPAD(HEX(nr),8,'0'), LPAD(HEX(nr2),8,'0'))); 
        
  RETURN output;
END$$
DELIMITER ;

希望这会有所帮助。但请注意:以这种格式保存密码是不安全的。

【讨论】:

    【解决方案3】:

    max 的回答很好,只是有时会失败。

    例如,当输入字符串为'my'时,返回值是一个长度为15而不是16的字符串。这是因为返回值的初始字符是0。试一试

    select old_password('my'); 
    

    确认这一点。

    补救方法是对 hex(nr) 和 hex(nr2) 应用 lpad() 函数 -- 以下行

    SET output = LOWER(CONCAT(HEX(nr), HEX(nr2)));
    

    应该改为

    SET output = LOWER(CONCAT(LPAD(HEX(nr),8,'0'), LPAD(HEX(nr2),8,'0'))); 
    

    【讨论】:

    • 这是一个很棒的发现。我已将这个答案的更改合并到 max 的相关答案中,因此错误不再存在(并且自编写以来还修复了一些错误)。
    • 感谢 mindconnect.cc 和 @JosefAdamcik,干得好!
    猜你喜欢
    • 1970-01-01
    • 2019-04-18
    • 1970-01-01
    • 1970-01-01
    • 2021-05-24
    • 2017-08-22
    • 2012-11-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多