【问题标题】:How to generate random string to salt passowrd in sql?如何在sql中生成随机字符串来加盐密码?
【发布时间】:2012-08-05 20:28:11
【问题描述】:

有一个问题在 sql 中加盐密码:

下面的代码通过随机生成一个 10 个字符的字符串来对特定密码进行加盐:

Update Teacher 
SET    TeacherSalt = SUBSTRING(MD5(RAND()), -10), 
       TeacherPassword = SHA1(CONCAT('009b9b624aaecc4b3217dcd4bfee15ab704745d7',SUBSTRING(MD5(RAND()), -10)))
WHERE TeacherPassword = '009b9b624aaecc4b3217dcd4bfee15ab704745d7'

但我的问题是我想更改盐,以便它生成的字符串来自所有这些字符:

./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789

共有 63 个字符。这样做的php方式如下:

$salt = ""; 
for ($i = 0; $i < 40; $i++) { 
   $salt .= substr(
     "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 
     mt_rand(0, 63), 
     1); 
}

但是上面的sql方式怎么写呢?

【问题讨论】:

  • 可能是错的,但我很确定TeacherSalt 中存储的值和用于创建TeacherPassword 的实际盐不等价。
  • 请注意,sha1() 算法对于密码哈希来说是一个非常弱的算法(因为它速度很快)。
  • 是的,我是说你执行了这个:SUBSTRING(MD5(RAND()), -10) 两次,你不会每次都得到相同的值。您需要保存盐,因此您无法摆脱TeacherSalt 列。在 PHP 中生成盐会更容易。
  • @user1394925 noooooooooooooooooooooo ;) MD5 完全损坏。使用bcrypt
  • 我的建议...不要...使用 PHP 和 crypt / bcrypt 创建您的散列并使用 PHP 检查它是否匹配。您正在使用一个非常旧的算法来加密,不建议再使用它。

标签: php mysql sql database salt


【解决方案1】:

如果你真的想随机加盐,那么只能通过使用 php 生成随机盐并用该盐加密密码并将盐密钥和密码存储在表的两个字段中来完成。表必须有盐字段和密码字段。但是,如果您只想使用 mysql 进行加密,请查看http://dev.mysql.com/doc/refman/5.5/en//encryption-functions.html

当我们验证用户的登录凭据时,我们遵循相同的过程,只是这次我们使用数据库中的 salt,而不是生成一个新的随机值。我们将用户提供的密码添加到其中,运行我们的哈希算法,然后将结果与存储在该用户配置文件中的哈希进行比较。

下面的链接可能会给你更多的想法。

How do you securely store a user's password and salt in MySQL?

Where do you store your salt strings?

How insecure is a salted SHA1 compared to a salted SHA512

Salt Generation and open source software

我希望你现在明白了。

【讨论】:

  • -1。 PASSWORD加密,密码应该总是被散列。文档甚至明确声明此功能不应在其他应用程序中使用。并且密码必须加盐。 绝对需要对密码进行加盐,加盐不能是硬编码或恒定的。硬编码的盐值是无用的盐值。
  • @AdamRobinson 我同意在存储时必须对密码进行哈希处理,直到现在我才意识到 mysql 中的 PASSWORD() 加密问题。感谢您强调这一点。我已经修改了答案。我希望你能投票。 :)
【解决方案2】:

简单来说,就是用 php.ini 搞定。首先从您的表格中获取信息(注意,使用自动递增的 ID 而不是密码 - 这可能不是唯一的 - 来选择您的行)

     function makeMeASalt($max=40){
         $i = 0;
         $salt = "";
         $characterList = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
         while ($i < $max) {
            $salt .= $characterList{mt_rand(0, (strlen($characterList) - 1))};
            $i++;
         }
         return $salt;
     }

     $hash=crypt($password.makeMeASalt(40))

     $query="Update Teacher 
         SET TeacherSalt = '".$salt."', TeacherPassword = ".$hash."
         WHERE TeacherID = '".$teacherid."'";
     mysql_query($query) or die(mysql_error())

这也消除了已经提到的盐在字段之间不一样的问题!

【讨论】:

    【解决方案3】:

    可以在 MySQL 中完成。随机词生成并不那么漂亮。关于生成和应用盐,这部分并不难。

    使用 2 个语句首先为每个人生成盐,然后应用它们。 (注意:如果你真的只想将它应用到一个帐户,那么添加一个 WHERE 子句。)

    mysql> select * from salty;
    +------+------+------+
    | id   | pw   | salt |
    +------+------+------+
    |    1 | fish | NULL |
    |    2 | bird | NULL |
    |    3 | fish | NULL |
    +------+------+------+
    

    (请注意,用户 1 和 3 恰好具有相同的密码。但您不希望它们在加盐和散列后相同。)

    mysql> update salty set salt=SUBSTRING(MD5(RAND()), -10);
    
    mysql> select * from salty;
    +------+------+------------+
    | id   | pw   | salt       |
    +------+------+------------+
    |    1 | fish | 00fe747c35 |
    |    2 | bird | ee4a049076 |
    |    3 | fish | 6a8285f03c |
    +------+------+------------+
    

    (注意:我稍后会显示特定字母版本)

    mysql> update salty set pw=sha1(concat(pw,salt));
    
    mysql> select * from salty;
    +------+------------------------------------------+------------+
    | id   | pw                                       | salt       |
    +------+------------------------------------------+------------+
    |    1 | ac1b74c36b4d2426460562e8710bd467bd034fc8 | 00fe747c35 |
    |    2 | d63d035f9cac1ac7c237774613b8b702d8c227df | ee4a049076 |
    |    3 | 6a0b1e36f489ef959badf91b3daca87d207fb5de | 6a8285f03c |
    +------+------------------------------------------+------------+
    

    你有两个语句,每一行都唯一地加盐和散列。

    现在对于随机生成指定字母的单词,ELT() 有一个丑陋的技巧。对于 64 个字母的 10 个字母的单词:

    UPDATE salty SET salt=CONCAT(
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64),  
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9'),
      ELT(1+FLOOR(RAND()*64), 
      '.','/',
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
      'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
      '0','1','2','3','4','5','6','7','8','9')
    )
    
    mysql> select * from salty;
    +------+------+------------+
    | id   | pw   | salt       |
    +------+------+------------+
    |    1 | fish | TzHO0e5I/k |
    |    2 | bird | 65xLptoDZ3 |
    |    3 | fish | JNok/SfmkG |
    +------+------+------------+    
    

    可怕,不是吗?但是在单个 MySQL 语句中执行此操作可能比在 PHP 中循环并在每行执行一个(或两个)查询要快得多,尤其是当您必须将其应用于具有数百万条记录的表时;一个丑陋的查询与一次进行数百万个查询。

    但正如其他人所说,SHA1 真的不再是一个足够好的哈希了。

    如果您确实有很多记录,那么使用几个类似的 MySQL 查询来更新所有记录以使用 SHA2 作为临时解决方案可能是有意义的,然后随着时间的推移将它们单独更新为更强的哈希值使用 PHP。当然,您需要一些方法来知道给定记录使用了哪个散列。

    附带说明,如果您只更新一行(如您的示例中所示),那么您也许可以使用 MySQL 变量来临时保存随机生成的字符串足够长的时间以更新该行的两列:

    mysql> SET @salt=SUBSTRING(MD5(RAND()), -10); UPDATE salty SET salt=@salt,pw=SHA1(CONCAT(pw,@salt)) WHERE id=2; SET @salt=NULL;
    

    这样,@salt 中的相同值用于设置 salt 和 pw 计算。但它不适用于更新多行(它们最终都会得到相同的盐)。

    【讨论】:

      【解决方案4】:

      我想在应得的地方给予表扬:雷的上述回答为我的回答提供了所有见解。在查看他的答案时,我实现了它,但是我通过使用函数和调用其他函数的函数清理了它的完成方式。这是雷的答案的清理版本。 (感谢 Ray 的精彩回复!)这也比让 php 生成它快得多。

      我创建了两个函数。第一个返回一个随机选择的字符。第二个递归调用第一个来构建任意长度的随机生成的字符串(例如在椒盐场景中使用等)。第二个限制为 255 的字符串长度,但是您可以轻松地对其进行修改。您可以将返回的字符更改为您想要的任何有效字符,只需记住计算数组中有多少个,从而将 64 更改为您输入的数量。我特意重新排列了 Ray 所拥有的数组中所有字符的顺序,只是为了使输出完全随机化。

      函数生成在默认情况下是被阻止的,并且必须通过脚本(我使用 Dbeaver)在命令行中输入,以便根管理员(在数据库上)可以是唯一进入它的人。我选择了这种更安全的方法,而不是像某些人推荐的那样更改我的日志记录,或者尝试在脚本开头定义函数的生成者。

      因为函数定义需要 ;包含在其中,必须首先将命令行分隔符更改为 $$,然后一旦完成输入的功能,将其更改回;这只是因为我是通过控制台而不是通过我的首选工具 (Dbeaver) 输入的。

      该函数不能使用 DECLARE,而必须使用 SET。 SET 变量名前面的 @ 是必需的,因为它表示我们正在设置用户定义的变量。

      现在是功能:

      /* Testing Purposes:
          SELECT f_generateRandomLetter64();
      */
      
      DROP FUNCTION IF EXISTS f_generateRandomLetter64;
      
      DELIMITER $$
      
      CREATE FUNCTION f_generateRandomLetter64()
      RETURNS varchar(1)
      CONTAINS SQL
      READS SQL DATA
      NOT DETERMINISTIC
      
      BEGIN
          SET @thisResult = '';
      
          SET @thisResult = ELT(1+FLOOR(RAND()*64), 
            '/','a','b','c','d','e','f','g','h','i','j','k','P','Q','R','S','T','U','V','W','X','Y','Z',
            '.','A','B','C','D','E','F','G','4','8','9','5','6','z','1','2','3','7','l','m','n','o','p',
            'q','r','s','H','I','J','K','L','M','N','O','t','u','v','w','x','y','0'
            );
      
          RETURN @thisResult;
      END $$
      
      DELIMITER ;
      

      下一个函数:

      /* Testing Purposes:
              SELECT f_generateRandomString(128);
              SELECT LENGTH(f_generateRandomString(10));
      */
      
      DROP FUNCTION IF EXISTS f_generateRandomString;
      
      DELIMITER $$
      
      CREATE FUNCTION f_generateRandomString(var_strLength int)
      RETURNS varchar(255)
      CONTAINS SQL
      READS SQL DATA
      NOT DETERMINISTIC
      
      BEGIN
          SET @thisResult = '';
      
        WHILE var_strLength > 0 DO
          SET @thisResult = CONCAT( @thisResult,f_generateRandomLetter64() );
          SET var_strLength = var_strLength -1;
        END WHILE;
      
          RETURN @thisResult;
      END $$
      
      DELIMITER ;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-02
        • 1970-01-01
        • 2011-04-30
        • 1970-01-01
        • 2013-07-26
        • 2016-09-16
        • 2019-10-14
        • 1970-01-01
        相关资源
        最近更新 更多