2008-09-05 122 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位數字。