質問

私は、ユーザーが電話をかけ、携帯電話のキーパッドで認証番号を入力する必要があるアプリケーションに取り組んでいます。

彼らが入力した数字が正しいかどうかを検出できるようにしたいと考えています。電話システムは有効な番号のリストにアクセスできませんが、代わりにアルゴリズム (クレジット カード番号など) に照らして番号を検証します。

要件の一部を次に示します。

  • 有効なランダムコードを入力するのは難しいに違いありません
  • タイプミス(数字の入れ替え、数字の間違い)をすると、有効なコードを取得するのは困難でしょう。
  • 適切な数の可能な組み合わせが必要です (100 万個としましょう)
  • ユーザーによるエラーを避けるために、コードはできるだけ短くする必要があります。

これらの要件を考慮すると、そのような数値をどのように生成しますか?

編集 :

@Haaked:ユーザーが携帯電話でコードを入力するため、コードは数値である必要があります。

@マットB:最初のステップでは、コードが Web ページに表示され、2 番目のステップでは、コードを呼び出して入力します。ユーザーの電話番号がわかりません。

フォローアップ :いくつかのアルゴリズムを見つけました チェック 数値の有効性 (この興味深い Google Code プロジェクトを参照してください: チェックディジット).

役に立ちましたか?

解決

いくつか調べた後、私はこれにしようと思います 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 => 良い
  • mod(21345676, 97) = 50 => 悪い!
  • mod(12345678, 97) = 10 => 悪い!

どうやら、このアルゴリズムはほとんどのエラーを検出するようです。

もう 1 つの興味深いオプションは、 バーホーフアルゴリズム. 。これには検証桁が 1 つしかなく、(上記の単純な式と比較して) 実装がより困難です。

他のヒント

1M の組み合わせの場合、6 桁が必要になります。誤って有効なコードが存在しないことを確認するために、ランダム コードが機能する確率が 1/1000 の 9 桁をお勧めします。また、別の数字 (合計 10) を使用して次のことを実行することをお勧めします。 整合性チェック. 。分布パターンに関しては、ランダムで十分であり、チェック デジットにより、単一のエラーが正しいコードにならないことが保証されます。

編集: どうやら私はあなたのリクエストを完全に読んでいなかったようです。クレジット カード番号を使用すると、その番号に対してハッシュ (MD5 または SHA1 など) を実行できます。次に、適切な位置 (たとえば 9 文字) で切り捨てられ、基数 10 に変換されます。次に、チェック ディジットを追加すると、目的に応じて多かれ少なかれ機能するはずです。

コードをセグメント化したいと考えています。その一部は、コードの残りの部分の 16 ビット CRC である必要があります。

検証番号だけが必要な場合は、シーケンス番号を使用してください (単一の生成ポイントがあると仮定して)。そうすることで、重複を取得していないことがわかります。

次に、シーケンス番号の CRC-16 と秘密キーをシーケンスの前に付加します。非公開にする限り、秘密キーには何でも使用できます。それを何か大きなものにしてください、少なくとも GUID, 、しかし、それはテキストかもしれません プロジェクト・グーテンベルクの戦争と平和. 。ただ秘密で一定である必要があります。秘密キーを持っていると、キーを偽造できなくなりますが、16 ビット CR を使用すると、解読が容易になります。

検証するには、番号を 2 つの部分に分割し、シーケンス番号と秘密キーの CRC-16 を取得します。

連続部分をさらに曖昧にしたい場合は、CRC を 2 つの部分に分割します。シーケンスの前に 3 桁、後ろに 2 桁を配置します (CRC の長さが一定になるようにゼロパッドします)。

この方法を使用すると、小さいキーから始めることもできます。最初の 10 キーは 6 桁になります。

数字だけでいいのでしょうか?1 から 1M の間の乱数を作成できます (ただし、それ以上をお勧めします)。 Base32でエンコードする. 。次に行う必要があるのは、その値を (秘密のソルト値を使用して) ハッシュし、そのハッシュを Base32 エンコードすることです。次に、2 つの文字列をダッシュ​​で区切って結合します。

こうすることで、受信したコードをアルゴリズム的に検証できます。コードの左側を取得し、シークレット ソルトを使用してハッシュし、その値をコードの右側と比較するだけです。

  • 妥当な数の可能な組み合わせが必要です (100 万個としましょう)
  • ユーザーによるエラーを避けるために、コードはできるだけ短くする必要があります。

少なくとも 100 万通りの組み合わせが必要な場合は、少なくとも 6 桁が必要です。それで十分ですか?

確認コードを作成するときに、発信者の電話番号にアクセスできますか?

その場合、発信者の電話番号を使用して、ある種のハッシュ関数を実行して、ステップ 1 で発信者に提供した確認コードが、ステップ 2 で入力したものと同じであることを保証できるようにします (確実にするため)。彼らは友人の認証コードを使用していないか、単に非常に幸運な推測をしただけです)。

ハッシュについては、10 桁の数値を受け取って 10 桁未満のハッシュ結果が得られるかどうかはわかりません (ある程度の衝突は覚悟しなければならないと思います)。これは、ユーザーが本人であることを確認するのに役立ちます。

もちろん、ステップ 1 で使用した電話番号がステップ 2 で発信した電話番号と異なる場合、これは機能しません。

ユーザーがどのキーを押したかを検出する方法をすでに知っていると仮定すると、これはかなり簡単に実行できるはずです。セキュリティの世界には、「ワンタイム」パスワードという概念があります。これは、「使い捨てパスワード」と呼ばれることもあります。通常、これらは(簡単に典型的な)ASCII値に制限されています。[a-zA-z0-9] と、簡単に入力できる記号の束です。カンマ、ピリオド、セミコロン、括弧など。ただし、あなたの場合は、範囲を [0-9] に制限し、* と # を含めることをお勧めします。

これらのワンタイムコードがどのように適切に生成される (または機能する) かという技術的な詳細をすべて説明することはできません。その背後には中間的な数学が含まれていますが、私はそれを最初に自分で確認せずに解体してしまいます。アルゴリズムを使用してワンタイム パスワードのストリームを生成すると言うだけで十分です。以前のコードをどれだけ知っていたとしても、後続のコードを推測することは不可能であるはずです。あなたの場合は、リスト上の各パスワードをユーザーのランダム コードとして使用するだけです。

私自身が実装の詳細を説明するのに失敗するのではなく、9 ページの記事を紹介しますので、ご自身で読んでください。 https://www.grc.com/ppp.htm

コードが有効であることをアルゴリズムによって迅速に判断する必要があるという暗黙の要件があるようですね。これにより、ワンタイムパッド番号のリストを単に配布することはできなくなります。

過去にこれを行う方法がいくつかありました。

  1. 公開鍵と秘密鍵を作成します。秘密キーを使用して 0 ~ 999,999 の数値をエンコードし、結果を配布します。結果を長いバージョンにするには、いくつかの乱数を投入する必要があり、結果を 64 進数から 10 進数に変換する必要があります。数値を入力したら、それを Base64 に変換し直し、秘密キーを適用して、興味深い数値が 1,000,000 未満かどうかを確認します (乱数は破棄します)。
  2. 使う 可逆ハッシュ関数
  3. 特定の値でシードされた PRN の最初の 100 万個の数値を使用します。「チェック」関数はシードを取得し、次の 100 万の値が適切であることを知ることができます。毎回それらを生成し、コードを受信したときに 1 つずつチェックすることも、100 万の整数はそれほど多くないため、プログラムの起動時にすべてをテーブルに格納して並べ替えてから二分検索 (比較の最大値) を使用することもできます。空間の。

他にもたくさんのオプションがありますが、これらは一般的で実装が簡単です。

-アダム

あなたがリンクしたのは、 チェックディジット プロジェクトを作成する場合、「エンコード」機能を使用するのが良い解決策のようです。こう書かれています。

「不正な」データの場合、エンコードは例外をスローする可能性があります(例:非数値) が渡されますが、verify は true または false のみを返します。ここでの考え方は、encode は通常、「信頼できる」内部ソース (たとえばデータベース キー) からデータを取得するため、不正なデータが渡されるのはごく普通のことであり、実際には例外的であるということです。

つまり、encode 関数にデータベース キー (たとえば 5 桁) を渡すと、要件を満たす数値を取得できるようです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top