14

几个月前,我的任务是为我们的 Web 应用程序实现一个独特的随机代码。代码必须对用户友好且尽可能小,但本质上仍然是随机的(因此用户无法轻易预测序列中的下一个代码)。

它最终生成了如下所示的值:

Af3nT5Xf2

不幸的是,我从未对实施感到满意。Guid 是不可能的,它们太大了,用户很难输入。我希望有更多的 4 或 5 个字符/数字,但如果我们编码为,我们的特定实现会产生明显的图案序列少于 9 个字符。

这是我们最终要做的事情:

我们从数据库中提取了一个唯一的连续 32 位 id。然后我们将它插入到一个 64 位 RANDOM 整数的中心位中。我们创建了一个易于键入和识别的字符(AZ、az、2-9 跳过容易混淆的字符,如 L、l、1、O、0 等)的查找表。最后,我们使用该查找表对 64 位整数进行 base-54 编码。高位是随机的,低位是随机的,但中心位是连续的。

最终的结果是一个比 guid 小得多的代码,而且看起来很随机,尽管它绝对不是。

我对这个特定的实现从来不满意。你们会怎么做?

4

6 回答 6

8

Here's how I would do it.

I'd obtain a list of common English words with usage frequency and some grammatical information (like is it a noun or a verb?). I think you can look around the intertubes for some copy. Firefox is open-source and it has a spellchecker... so it must be obtainable somehow.

Then I'd run a filter on it so obscure words are removed and that words which are too long are excluded.

Then my generation algorithm would pick 2 words from the list and concatenate them and add a random 3 digits number.

I can also randomize word selection pattern between verb/nouns like

eatCake778
pickBasket524
rideFlyer113 etc..

the case needn't be camel casing, you can randomize that as well. You can also randomize the placement of the number and the verb/noun.

And since that's a lot of randomizing, Jeff's The Danger of Naïveté is a must-read. Also make sure to study dictionary attacks well in advance.

And after I'd implemented it, I'd run a test to make sure that my algorithms should never collide. If the collision rate was high, then I'd play with the parameters (amount of nouns used, amount of verbs used, length of random number, total number of words, different kinds of casings etc.)

于 2008-08-29T16:58:12.253 回答
3

在 C# 中,我使用了 ' System.IO.Path.GetRandomFileName() : String ' 方法......但我正在为调试文件名生成盐。这个方法返回的东西看起来像你的第一个例子,除了随机的“.xyz”文件扩展名。

如果您在.NET 中并且只想要一个更简单(但不是“更好”的)解决方案,我会说就是这样......如果您愿意,您可以删除随机文件扩展名。

于 2008-08-29T16:53:34.950 回答
3

In .NET you can use the RNGCryptoServiceProvider method GetBytes() which will "fill an array of bytes with a cryptographically strong sequence of random values" (from ms documentation).

byte[] randomBytes = new byte[4];
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
rng.GetBytes(randomBytes);

You can increase the lengh of the byte array and pluck out the character values you want to allow.

于 2008-08-29T16:56:29.450 回答
2

在撰写本文时,这个问题的标题是:

如何生成唯一、小的、随机且用户友好的密钥?

对此,我应该注意,通常不可能创建一个也是唯一的随机值,至少如果每个随机值是独立于其他任何值生成的。此外,如果您想生成唯一标识符(来自我的唯一随机标识符部分),您应该问自己很多事情:

  1. 应用程序能否轻松检查标识符在所需范围和范围内的唯一性(例如,检查具有该标识符的文件或数据库记录是否已经存在)?
  2. 应用程序能否容忍为不同资源生成相同标识符的风险?
  3. 标识符是否必须难以猜测,只是“随机外观”,或者两者都不是?
  4. 标识符是否必须由最终用户输入或以其他方式传递?
  5. 标识符标识的资源是否可供知道该标识符的任何人使用(即使没有登录或以某种方式授权)?
  6. 标识符必须是令人难忘的吗?

在您的情况下,您有几个相互冲突的目标:您想要的标识符是——</p>

  • 独特的,
  • 易于最终用户(包括小型用户)键入,以及
  • 难以猜测(包括随机)。

您在问题中未提及的要点包括:

  • 密钥将如何使用?
  • 是否允许其他用户在知道密钥时访问由密钥标识的资源?如果不是,则需要额外的访问控制或更长的密钥长度。
  • 您的应用程序可以容忍重复密钥的风险吗?如果是这样,那么密钥可以完全随机生成(例如通过加密 RNG)。如果不是,那么您的目标将更难实现,特别是对于用于安全目的的密钥。

请注意,我不会讨论将唯一值格式化为“用户友好键”的问题。有很多方法可以做到这一点,它们都归结为将唯一值与“用户友好键”一对一映射——如果输入值是唯一的,那么“用户友好键”同样也是唯一的。

于 2020-07-15T17:18:32.927 回答
0

If by user friendly, you mean that a user could type the answer in then I think you would want to look in a different direction. I've seen and done implementations for initial random passwords that pick random words and numbers as an easier and less error prone string.

If though you're looking for a way to encode a random code in the URL string which is an issue I've dealt with for awhile then I what I have done is use 64-bit encoded GUIDs.

于 2008-08-29T17:07:09.050 回答
0

You could load your list of words as chakrit suggested into a data table or xml file with a unique sequential key. When getting your random word, use a random number generator to determine what words to fetch by their key. If you concatenate 2 of them, I don't think you need to include the numbers in the string unless "true randomness" is part of the goal.

于 2008-08-29T18:20:03.853 回答