5

有一个在 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方式写这个呢?

4

4 回答 4

6

它可以在 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 计算。但是,它不适用于更新多行(它们最终都会得到相同的盐)。

于 2012-11-02T01:06:20.727 回答
3

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

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

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

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

你在哪里存放你的盐串?

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

Salt Generation 和开源软件

我希望你现在明白了。

于 2012-10-22T03:09:23.127 回答
1

简单来说,就是用 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())

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

于 2012-11-01T12:25:27.593 回答
0

我想在应得的地方给予赞扬:雷的上述回答为我的回答提供了所有见解。在查看他的答案时,我实现了它,但是我通过使用函数和调用其他函数的函数清理了它的完成方式。这是雷的答案的清理版本。(感谢 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 ;
于 2021-04-20T19:35:39.757 回答