【问题标题】:How would I securely generate a password that contains certain characters?如何安全地生成包含某些字符的密码?
【发布时间】:2020-12-16 07:29:19
【问题描述】:

创建密码时,有时我需要密码包含大写、小写、数字或符号。如果我这样创建密码,则不能保证每个密码都被表示:

$input = 'a..zA..Z0..9$!_'; // generally the whole allowed alphabet
while (strlen($password) < 10) {
  $password .= securelyPickRandomCharacterFromString($input);
}

在这种情况下,随机过程(即使它是安全且完全随机的)有可能只选择小写字母。

我可以想到一些幼稚的方法,例如首先从每个组中选择 1 个,然后随机填充其余的。但这不会像 random_bytes() 那样在密码学上是安全的。也许之后洗牌?

什么是生成包含每个“组”字符的密码的好且安全的算法。

注意:密码要求通常是针对外部系统的,我无法控制。

【问题讨论】:

  • 如您所说,从每个组中选择一个,其余的从所有组中随机选择。然后随机播放。
  • 如果您丢弃其中一个 $input 字符,那么使用简单的方法会更容易,因为长度是 256 的除数。否则,您选择的标准库通常具有辅助函数在这里实现一些有用的东西。如果您只有random_bytes() 可用,那么它是可行的,但具有挑战性。

标签: random cryptography passwords


【解决方案1】:

这是一种非常幼稚的做法(伪代码):

// Create your lists/arrays of groups
char listLowerCase[] = {'a','b',....};
char listUpperCase[] = {'A','B',....}; 
char listNums[] = {'1','2',....};
char listSpecialChars[] = {'@','#',...};

// Form a password from those groups (I'm just gonna use length 4 as example)
String pwd = listLowerCase[randomNumber] + listUpperCase[randomNumber] 
             + listNums[randomNumber] + listSpecialChars[randomNumber];

// Shuffle the password
String shuffledPwd = shuffle(pwd);

如果您不希望每个组中的字符数相同,您也可以尝试设置随机数来确定您将在每个组中使用多少个字符。希望对您有所帮助。

【讨论】:

    【解决方案2】:

    到目前为止,最简单的方法是使用所选字母生成随机密码。然后检查诸如“必须包含每个字符类中的至少一个”之类的约束。如果密码与约束不匹配,请循环重试。

    do {
      $password = '';
      while (strlen($password) < 10) {
        $password .= securelyPickRandomCharacterFromString($input);
      }
    } while (!matches_constraints($password));
    

    在可接受密码的给定限制内,这具有最佳安全性,因为所选长度的每个可接受密码的可能性均等。

    除了简单性和安全性之外,这种方法的另一个好处是它可以适应任意约束,例如常见的“必须包含至少 4 个字符类中的 3 个”,而无需为每个不同的约束编写不同的复杂代码.

    使用任何合理的参数,重绘的次数都会很少。例如,从非空格可打印 ASCII 字符(94 个字符的字母表)生成的 10 个字符的密码有 ((94-10)/94)^10 ≈ 0.32 的机会不包含数字,即四个字符中最小的一个类。错过四个班级之一的机会略低于 0.42。因此,平均而言,您需要少于 2 次迭代来获得具有这些特定参数的合适密码。生成随机字母很便宜,所以性能不是问题。

    您应该包括对无意义参数的保护,例如尝试生成包含所有 4 个类别的字符的 3 字符密码(将永远循环),或包含所有 4 个类别的字符的 4 字符密码(其中可能需要很长时间)。所以添加一个最大迭代次数。

    $iterations = 0;
    do {
      if ($iterations >= 10) throw new NonsensicalPasswordConstraintException;
      $password = '';
      while (strlen($password) < 10) {
        $password .= securelyPickRandomCharacterFromString($input);
      }
      ++$iterations;
    } while (!matches_constraints($password));
    

    【讨论】:

      猜你喜欢
      • 2013-01-02
      • 2017-01-15
      • 2019-09-03
      • 2013-04-01
      • 2016-09-12
      • 2022-01-17
      • 2020-04-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多