RFC4226は、HOTPアルゴリズムを「増加するカウンター値と、トークンと検証サービスだけが知っている静的対称鍵に基づく」と説明しています。具体的には、次のとおりです。
HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))
各ユーザーが独自のカウンターを持っていると仮定して、カウンター(つまりアルゴリズムのC部分)を保存するにはどうすればよいですか?
あなたの質問への答えは、あなたが正確に何のためにカウンター値を使用しているかに依存します。
さまざまなOTPスキームがあります。 1つはHOTPがカウンターを使用しているため、HOTPの実装について話しているのかもしれません。ただし、あなたの質問は、有効なパスワードのリストがあり、次の有効なパスワードを覚えておく必要があることを示唆している可能性もあります。これは私を完全に悪い考えだと思います、そしてあなたはそれを簡単に改善し、同時にあなたのカウンターの問題を解決することができます。したがって、HOTPカウンターまたは同様のソリューションについて話しているのでない場合は、次の提案があります。
すでに「使い果たされた」パスワードを保持する必要はありません。古いパスワードは使用されなくなったため、保持することが問題になる理由はすぐにはわかりませんが、保持する必要がない場合は、必ず破棄します。これらのパスワードを何に使用しているかによっては、たとえば、パスワードを保持することで前方セキュリティを危険にさらす可能性があります。
古いパスワードを破棄すると、カウンターの問題も修正されます。次の有効なパスワードはリスト内の次のパスワードであるため、カウンターを保持する必要はまったくありません。また、常に次のパスワードを取得するのではなく、残りのパスワードの1つをランダムに選択することで、セキュリティを少し強化することもできます。
ただし、ランダムなパスワードの選択が必要ない場合は、より簡単な解決策があります。たとえば、パスワードのリストを保存する必要がない、より簡単な解決策です。
HOTPは基本的に、シークレットとカウンターを指定してhmacを構築し、その結果をパスワードとして使用します。 TOTPは代わりに時間を使用するため、パスワードの紙のリストでは使用できませんが、OTPの有効期限が切れることができるという利点があります。
編集:更新/編集された質問により適切に回答するために、このセクションを追加しました
HOTPを使用するときに心配する必要があるのは、カウンターを安全に保つかどうかではなく、使用している秘密を安全に保つ方法だと思います。攻撃者が秘密鍵にアクセスした場合、攻撃者は過去および将来のすべてのパスワードを生成できます。この知識があれば、彼は試行するカウンター値の範囲を推測するかもしれません。シークレットがないと有効なパスワードを作成できないため、カウンター値自体の知識はそれほど危険ではありません。
したがって、秘密鍵を安全に保管するための解決策がすでに必要であるため、注意を怠って同じ方法でカウンター値を保管することができるように思われます。それが必要ない場合は、データベースのユーザーテーブルに列を追加し、そこにカウンター値を格納するだけです。
あなたcouldこのカウンター値を別のパスワードを使用して事前に暗号化します(ランダムなivなので、同じカウンター値は同じ暗号文を生成しません!)が、率直に言って、次の理由であまり利益が見られません。
Lamport OTPは、共有シークレットを必要とせず、検討することもできるOTPのシンプルで美しいソリューションです。
基本的に、アイデアはハッシュのハッシュのハッシュをハッシュすることです。それがどのように機能するかについての簡単なアイデアについては、次のOTPソリューションを検討してください。安全なパスワードハッシュ関数H(x)を取り、最初のランダムをハッシュします。あなただけが知っているシードシークレットS。ユーザーのパスワードのリストを生成するには、結果を取得して、必要な数のパスワードを生成するために必要な回数だけ、何度も何度もハッシュします。つまり、基本的にはOTPSのリストを作成していることになります。
[ H(S), H(H(S)), H(H(H(S))), ...]
ここでの問題の1つは、ハッシュをパスワードとして直接使用する場合、攻撃者がハッシュの1つだけを学習すると、将来のすべてのハッシュも計算できることです。
これはさまざまな方法で修正できます。たとえば、could結果のハッシュを取得し、それをパスワードとして使用して別の秘密の文字列を暗号化し、暗号化された文字列をパスワードとして使用してリストに追加し、検証します。 (私はちょうどそれを作りました-おそらくそうではないので、これが安全であるかどうかを慎重に考えずにこれを使用しないでください)。
LamportOTPはそれをはるかに賢くします。基本的にはハッシュを逆方向に送信します。例えばシードに基づいて最初の100個のハッシュを計算し、逆の順序でそれらのリストをユーザーに提供します。したがって、彼が最初に送信するのは100番です。
彼が次に送信するのは99番です。サーバーはH(OTP99) = OTP100かどうかを確認できます。ハッシュ関数は一方向であるため、OTP100を知っていても攻撃者は取得できません。 OTP99で。
ここでの良い点は、サーバーが危険にさらされる可能性のあるものを保存する必要がないことです。最後に送信されたパスワード(ハッシュなど)をどこかに保存する必要があるため、最初はOTP101の値を持っている必要があり、ユーザーがOTP100で正常にログインすると、OTP101をOTP100に置き換える必要がありますが、攻撃者がサーバー側で現在保存されている値を知ることは、彼が実際に知る必要があるのはS(または派生ハッシュのいずれか)であり、クライアントで安全であることが望まれるため、彼の助けにはなりません。サーバーはSを保存する必要はまったくありません。つまり、サーバーに保存するパスワードとOTP101のリストを生成した後は、SまたはOTP 1〜100のいずれかを知る必要がなくなります。これは、カウンター値を安全に保つ必要があるかどうかという質問を完全に回避する非常に美しいソリューションだと思います。Lamportでは、サーバー側で安全に保つものは何もありません。
少し簡略化して、アルゴリズム/プロトコルを読んで、これを詳細に実装する方法を確認しました。
@Pascalが指摘したように、キー「K」を暗号化する必要があります。ただし、暗号化キーをどこに保存するかも考慮する必要があります。
単純なアプローチ
システムで暗号化キーを使用します。暗号化キーは、ハードディスク上のファイルです。データベース内の[〜#〜] k [〜#〜]を暗号化するために使用されます。データベースは、DBMS管理者によって管理されている別のマシンにある可能性があります。このようにして、盗まれたデータベースがトークンの[〜#〜] k [〜#〜]を危険にさらさないことを確認できます。
ただし、同じマシンで実行している場合は、暗号化された[〜#〜] k [〜#〜]と暗号化キーを盗むことができます。
したがって、サーバーを強化し、サーバーへのアクセスを制御する必要があります。
オフライン攻撃に対してより安全
同じマシンで実行している場合は、暗号化キーを暗号化できます。パスワードを使用して暗号化キーを暗号化します。サービスを開始すると、パスワードを入力できるため、暗号化キーはRAMで復号化され、[〜#〜] kを復号化するために使用できます。データベース内の[〜#〜]。
最も洗練されたアプローチ
暗号化キーを保存するには、ハードウェアセキュリティモジュールを使用します。 [〜#〜] k [〜#〜]をinsideで復号化する-)HSM。任意のHSMを使用できます。
最も洗練されたものよりも
HOTPを実行するようにプログラムできる汎用HSMを使用します。このようにして、すべての[〜#〜] k [〜#〜]をHSM内に保持できます。実際のライブで復号化する必要はありません。 HSMに特定のカウンターの次のOTP値を計算させます。カスタムのプログラム可能なHSMを使用できます。