如何在 sql 中生成随机字符串来加盐


How to generate random string to salt passowrd in sql?

在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 方式编写它呢?

它可以在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中的相同值将用于凝固盐和 pw 计算。 不过,它不适用于多行的更新(它们最终都会得到相同的盐)。

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

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

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

如何在 MySQL 中安全地存储用户的密码和盐?

你把盐串存放在哪里?

盐渍 SHA512 相比,盐渍 SHA1 有多不安全

制盐和开源软件

我希望你现在明白了。

简单地说,用php来解决它。首先从表中获取信息(请注意,使用自动递增的 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())

这也摆脱了已经提到的问题,即您的盐在田间不相同!

我想

在适当的时候给予荣誉:Ray上面的回答为我的回答提供了所有的见解。在查看他的答案时,我实现了它,但是我通过使用函数和调用其他函数的函数清理了完成它的方式。这是雷的答案的清理版本。(感谢雷的好评!这也比让 php 生成它快得多。

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

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

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

该函数不能使用 DECLARRE,必须改用 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 ;