【问题标题】:Will C# system.Random with 14 characters always be guaranteed to be unique string (hash)14 个字符的 C# system.Random 是否总是保证是唯一的字符串(哈希)
【发布时间】:2017-10-31 08:21:02
【问题描述】:

我有一个实用程序函数,我想将它作为我的 URL 查询字符串的一部分。我需要确保它始终是独一无二的

public static string RandomString(int length)
{
   const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz0123456789";
   var random = new Random();
   return new string(Enumerable.Repeat(chars, length)
     .Select(s => s[random.Next(s.Length)]).ToArray());
}

如果说我传入 14 作为长度,这会生成类似哈希

 YS5bwVTjwEBhFp
 sNi6EfU5rUxI2Z
 sQKhqhklw22vb2

如果我说它一年使用 20,000 次,是否可以肯定地说它应该始终是独一无二的?

再次

http://:mywebsite.com?id=sQKhqhklw22vb2 是我将如何使用它

【问题讨论】:

  • 当然,假设是不安全的。 Random 不存储去年所有先前调用的结果,通过反射识别调用方法,然后说,“哦,又是米勒,生成哈希。确保他得到一些新的!”
  • Random 不承诺唯一性。
  • 对于全球唯一 ID,请使用... GUID。
  • 使用转换为字符串的 Guid,它不会是唯一的,但碰撞的机会很小,被认为是唯一的。
  • 事实上,非常严重的是,如果Random 在一段时间内没有重复序列,它就会随机性降低。如果您今天看到“4,0,1,0,4,0,1,0”,您可以确定明天不会看到它。

标签: c# asp.net random hash


【解决方案1】:

确保唯一性的一种方法是保存生成的值并在使用之前验证过去从未使用过的值。另一种方法是预先生成大量值,将它们保存在表中,然后选择下一个可用值。这个主题的变化是确保独特性的唯一方法 如果参数没有意义(没有语义)。

另一种方法是添加含义。而不是YS5bwVTjwEBhFpsNi6EfU5rUxI2Z 等使用01 等(来自数据库的增量值)。当然,您可以对此进行编码,例如。通过加密,变成一个对用户没有意义的值,所以用户仍然看到sNi6EfU5rUxI2Z,但那是1的base64编码加密值或类似的东西。

最后,对于所有实际用途,仅使用加密随机字符串(即RNGCryptoServiceProvider.GetBytes)就足够了。不保证独一无二,但极不可能发生冲突。

【讨论】:

  • 基于当前时间戳的操作怎么样?像哈希什么的?这是个好主意吗?
  • 那么这个RNGCryptoServiceProvider.GetBytes 好多了?你能告诉我如何使用它的例子吗?
  • @degant 严格来说,时间戳的唯一性哈希可能与其他任何东西一样唯一。但历史上充满了对可预测哈希的成功密码攻击。随机生成的字符串更好。
  • 我正在阅读Guffa对类似问题的回复stackoverflow.com/questions/16616521/…
【解决方案2】:

不确定您的 System.Random 是否如此出色,但您可以结合使用更好的密码学方案。你的 10 个角色和 40 个更好的角色......

它在 Linqpad 中

例子:你的生成h0UcVayzu2 另一个更好的生成LyR7SUYZ-ZPll36wzGI5kMPamKtyXV_rN0Ax6iZG

组合是 50 个字符

h0UcVayzu2LyR7SUYZ-ZPll36wzGI5kMPamKtyXV_rN0Ax6iZG

代码:

void Main()
{

    var x = RandomString(10);
    x.Dump();

    var y = Example.GenerateIdentifier(40);
    y.Dump();

    var z = x + y;

    z.Dump();


}


public static string RandomString(int length)
{
  const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz0123456789";
  var random = new Random();
  return new string(Enumerable.Repeat(chars, length)
    .Select(s => s[random.Next(s.Length)]).ToArray());
}


public class Example {
  static readonly char[] AvailableCharacters = {
    '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', '-', '_'
  };

  internal static string GenerateIdentifier(int length) {
    char[] identifier = new char[length];
    byte[] randomData = new byte[length];

    using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider()) {
      rng.GetBytes(randomData);
    }

    for (int idx = 0; idx < identifier.Length; idx++) {
      int pos = randomData[idx] % AvailableCharacters.Length;
      identifier[idx] = AvailableCharacters[pos];
    }

    return new string(identifier);
  }
}

【讨论】:

    猜你喜欢
    • 2011-03-05
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    • 2019-02-03
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    相关资源
    最近更新 更多