2008-09-05 85 views
24

我正在开发一个应用程序,用户必须拨打电话并使用手机的键盘键入验证号码。如何生成验证码/号码?

我希望能够检测他们输入的数字是否正确。电话系统无法访问有效号码列表,但会根据算法(如信用卡号码)验证号码。

这里有一些要求:

  • 它必须是很难键入一个有效的随机码
  • 它必须是很难有一个有效的代码,如果我做一个错字(数字换位,错数字)
  • 我必须有可能的组合reasonnable数(比如说1M)
  • 代码必须尽可能短,以避免用户错误

鉴于这些要求,你会如何产生这样的数字?

编辑:

@Haaked:代码必须是数字的,因为用户键入它与它的手机。

@matt b:第一步,代码显示在网页上,第二步是调用并键入代码。我不知道用户的电话号码。 Folowup:我发现了几种算法来检查数字的有效性(请参阅这个互动的谷歌代码项目:checkDigits)。

+0

+1,感谢您的跟进链接。 – 2009-09-12 15:52:01

回答

29

经过一番研究,我觉得我会用ISO 7064 Mod 97,10配方。它似乎非常稳固,因为它用于验证IBAN(国际银行帐户号码)。

的公式是非常简单的:

  1. 获取数字:123456
  2. 运用以下公式来获得2位校验:mod(98 - mod(number * 100, 97), 97) => 76
  3. 的毗连数和校验和来获得的代码=> 12345676
  4. 为了验证代码,验证mod(code, 97) == 1

测试:

  • mod(12345676, 97) = 1 => GOOD
  • mod(21345676, 97) = 50 = BAD>!
  • mod(12345678, 97) = 10 =>坏!

显然,这个算法捕获了大部分错误。

另一个有趣的选择是Verhoeff algorithm。它只有一个验证码,实施起来比较困难(与上面的简单公式相比)。

+0

如果期望有敌意的用户(这似乎暗示了这个问题),用户使用这种算法很容易生成有效的ID。 – 2009-07-09 12:42:17

4

对于1M组合,您需要6位数字。为了确保没有任何意外的有效代码,我建议9位数的1/1000几率随机代码工作。我还建议使用另一个数字(总共10个)来执行integrity check。就分布模式而言,随机就足够了,校验位将确保单个错误不会导致正确的代码。

编辑:显然我没有完全阅读您的请求。使用信用卡号码,您可以对其执行散列(MD5或SHA1或类似的)。然后在适当的位置截断(例如9个字符)并将其转换为基数10.然后添加校验位,这应该或多或少适用于您的目的。

0
  • 我必须有可能的组合reasonnable数(比如说1M)
  • 代码必须尽可能短,从用户避免错误

好,如果您希望它至少有一百万个组合,那么您至少需要六位数字。这足够短了吗?

0

当您创建验证码时,您是否可以访问来电者的电话号码?

如果是这样,我将使用呼叫者的电话号码并通过某种哈希函数运行它,以便您可以保证在步骤1中给予呼叫者的验证码与他们在步骤2中输入的验证码相同(以确保他们没有使用朋友的验证码,或者他们只是非常幸运的猜测)。

关于哈希,我不确定是否有可能获得一个10位数的数字,并出来一个哈希结果,将是< 10位数字(我想你必须忍受一定量的碰撞),但我认为这有助于确保用户是他们自称的人。

当然,如果在步骤1中使用的电话号码,这是不行的是比他们从步骤调用一个不同2.

1

是否必须是唯一的数字?你可以创建一个1到1M的随机数(我建议更高),然后Base32 encode it。接下来你需要做的是哈希值(使用秘密盐值)和base32对哈希进行编码。然后将两个字符串附加在一起,也许由短划线分开。

这样,您可以算法验证传入的代码。你只需要代码的左侧,使用你的秘密盐进行哈希,并将该值与代码的右侧进行比较。

0

假设您已经知道如何检测用户击中哪个键,这应该是合理轻松可行的。在安全领域,有一个“一次性”密码的概念。这有时被称为“一次性密码”。通常情况下,这些仅限于(易于打字的)ASCII值。所以,[a-zA-z0-9]和一堆容易打字的符号。如逗号,句号,分号和括号。不过,对于您的情况,您可能希望将范围限制为[0-9],并可能包括*和#。

我无法解释如何充分生成(或工作)这些一次性代码的所有技术细节。在它背后有一些中间数学,我不会先亲自审查它,而是让它成为屠夫。只需说您使用算法来生成一次性密码流即可。不管你知道以前的代码如何,后面的代码应该是无法猜测的!在你的情况下,你只需使用列表中的每个密码作为用户的随机代码。

,而不是在解释自己的执行细节失败了,我会领你到一个9页的文章,你可以在上面youself读了起来:https://www.grc.com/ppp.htm

0

这听起来像你有潜需求,它必须通过算法快速确定代码是有效的。这将排除你只是发出一个一次性垫号的列表。

以前有几种方法可以做到这一点。

  1. 制作公钥和私钥。使用私钥编码数字0-999,999,并分发结果。您需要输入一些随机数字以使结果出现在更长的版本中,并且必须将结果从基数64转换为基数10.当您输入一个数字时,将其转换回base64,应用私人密钥,并查看分数是否低于1,000,000(丢弃随机数)。
  2. 使用a reversible hash function
  3. 使用从特定值播种的PRN中的第一百万个数字。 “检查”功能可以获得种子,并且知道下一百万个值是好的。它可以每次生成它们并在接收到代码时逐一检查,或者在程序启动时将它们全部存储在一个表中,进行排序,然后使用二分查找(最大比较),因为一百万个整数不是很多的空间。

还有一堆其他选项,但这些选项很常见,也很容易实现。

- 亚当

0

您链接到check digits项目,并使用“编码”功能似乎是一个很好的解决方案。它说:

如果'坏'数据(例如非数字)传递给它,而验证只返回true或false,则encode可能会抛出异常。这里的想法是,编码通常得到它的数据来自“可信的”内部资源(例如数据库密钥),所以它应该是相当平常,事实上,卓越的坏数据正在被通过。

所以这听起来像你可以通过编码功能的数据库密钥(例如5位数字),你可以得到一个数字,以满足您的要求。

2

你想分割你的代码。其中一部分应该是其余代码的16位CRC。

如果你想要的只是一个验证码,那么就使用一个序列号(假设你有一个单一的生成点)。这样你就知道你没有得到重复。

然后你在该序列前加一个序列号和一些私钥的CRC-16。只要您保密,您可以使用任何私钥。让它变大一点,至少是GUID,但它可能是War and Peace from project Gutenberg的文字。只需要保密和不变。拥有私钥可以防止人们伪造密钥,但使用16位CR可以更容易地破解密钥。

要验证您只需将数字拆分为两部分,然后取一个序列号和私钥的CRC-16。

如果您想更多地隐藏顺序部分,则将CRC分为两部分。在序列的前面放置3位数字,并在后面放置2位数(零填充,所以CRC的长度一致)。

该方法允许您从更小的键开始。前10个键将是6位数字。