web-dev-qa-db-ja.com

次の認証スキームは安全ですか?

私は、ブルートフォースによるパスワードの推測をはるかに困難にし、ハッシュされたパスワードがスヌーピングベースの攻撃によって盗まれた場合のユーザーへのリスクを軽減する認証システムを設計しようとしていました。また、私のクライアント側のコードは、それを表示したい人が簡単に表示できるため(これはインタープリター言語ですが、分散クライアントを暗号化して難読化しています)、攻撃者が見ているのを防ぐことができたかったですユーザーを簡単に偽装するためのソース。あいまいさによるセキュリティは[〜#〜] not [〜#〜]セキュリティです。

これが私が考えたアルゴリズムです。 IMHOは、可能な限り多くの意見を受けた場合に暗号化アルゴリズムが常により適切に機能するため、私はそれを公開審査に提出したいと思いました。


(すべてのハッシュは、SHA-2と512ビットのブロックサイズで計算されます。このアルゴリズムは、衝突やプリイメージ攻撃に対して脆弱であるとは考えられておらず、安全な暗号化ハッシュ関数です。)

[クライアント側]

  1. ユーザーは、30文字未満の任意の文字/記号/数字のユーザー名と、8〜200文字の任意の文字/記号/数字のパスワードを入力します。

  2. ユーザー名はハッシュ化されています。

  3. ユーザー名のハッシュは、ソルトとしてユーザーのパスワードの最後に追加されます。

  4. ソルトされたパスワードがハッシュされ、そのハッシュがハッシュされます。

  5. 現在の日付と時刻が認証サーバーから要求され、ハッシュされます。

  6. タイムスタンプのハッシュは、「時間依存ソルト」と呼ばれるものとして、ユーザー名/パスワードハッシュに追加されます。次に、この最後の組み合わせをハッシュして、最終的な認証ハッシュを生成します。

  7. ユーザー名、タイムスタンプ付きハッシュ、ソルトパスワード、および時間依存ソルトの生成に使用された時間は、TLS/SSL接続を介してサーバーに送信されます。

[サーバー側]

  1. サーバーは、受信したタイムスタンプが最後の分にあることを確認します。そうでない場合、サーバーは認証が失敗したことを示します。

  2. サーバーはユーザー名/ソルト化されたパスワードをハッシュし、保存されているデータベースのソルト化/パスワードハッシュと比較します。それらが一致しない場合、認証は失敗します。 (明確にするために、サーバーにはソルト付きパスワードハッシュのハッシュがあります。クライアントから提供されたソルト付きパスワードハッシュのハッシュと照合して検証します。)

  3. サーバーは、クライアントが送信したタイムスタンプのハッシュを計算します。

  4. サーバーは、生成されたタイムスタンプハッシュとソルトパスワードハッシュをハッシュして、認証ハッシュを形成します。

  5. 生成した認証ハッシュとクライアントが送信した認証ハッシュを比較します。それらが同じである場合、認証を報告します。それ以外の場合は、認証の失敗を報告します。


私が正しければ、この認証スキームは確かにパスワードの総当たり攻撃をほぼ不可能にし、スヌーピングによって盗まれたパスワードは1分間だけ役に立ちます。

ただし、保護できないのは、不可能だと思うのですが、クライアントへの入力時にユーザーから盗まれたパスワードです。スパイウェアは、実際のユーザー名とパスワードを盗むことができます。

編集1 ::サーバーがソルトされたパスワードハッシュを保存せず、その値のハッシュのみを保存するように認証プロセスを修正しました。これにより、データベースにアクセスできる攻撃者が元のパスワードを知ることを防ぎます。これを行わなければならない理由は、ソルトされたパスワードハッシュのハッシュ値isサーバーの観点から見たパスワードです。データベースにソルトパスワードハッシュを格納することは、すべてのユーザーのパスワードをプレーンテキストで格納することと同じです。

編集2 ::認証がクライアントではなくサーバーの時間に依存するようにスキームを修正しました。

編集 ::パスワードの長さの制限を緩和しましたが、妥当な長さにしました。

7
Josh

SSL/TLSを通過する場合、サーバー認証(クライアントは適切なサーバーと通信していることが確実です)と送信データの機密性と整合性が保証されているため、恐れるスヌーピングはありません。発生した場合、それはクライアントまたはサーバー上で正しくなければなりません。その時点で、より大きな問題が発生します(攻撃者がクライアントで送信データを直接読み取ることができる場合、攻撃者はおそらくキーストロークもログに記録できます)。

パスワードハッシュスキーム自体を検討する場合(つまり、SSL/TLSを考慮しない場合)、いくつかの問題があります。

  • あなたは単にそれを追加することによってあなたの「塩」を含めます。これがSHA-512で問題を引き起こさないという証拠はありません。 SHA-512は Merkle-Damgård ハッシュ関数です。つまり、これは理想的ではないということです。それはいくつかの構造を持っています(例えば「長さ拡張攻撃」)。これは、SHA-512が壊れているという意味ではありません。 ランダムOracle であるかのように処理するだけですが、衝突やプリイメージに対しては「ただ」耐性があります。
  • ハッシュ関数の呼び出しを十分に繰り返していない。これによりプロセスが速すぎます。結果のハッシュを観察する攻撃者は潜在的なパスワードを「試行」する可能性があり、高速で実行できます(単純なPCで1秒あたり数百万のパスワード)。これは「辞書攻撃」と呼ばれ、ユーザーが適切なパスワードを選択して覚えるのが苦手なため、うまく機能する傾向があります。
  • SHA-256の代わりにSHA-512を使用します。あなたは「解釈された言語」について話します:それがJavascriptであるならば、その言語は64ビット操作(SHA-512はそれらでいっぱいです)で非常に非効率です、それでSHA-256の代わりにSHA-512を使うことは厳しく数を制限しますクライアントシステムで実行できる反復。これにより、辞書攻撃の効率が向上します。

パスワードハッシュの通常の推奨事項は PBKDF2bcrypt および scrypt (私の個人的なお気に入りはbcryptです。PBKDF2は当初そのために設計されていませんでした。scryptはまだ新しすぎて、一般に信頼できません)。

設計上、オフラインの辞書攻撃の影響を受けない認証プロトコルがあります。それらは Password-Authenticated Key Exchange と呼ばれます。 PAKEプロトコルは、クライアントとサーバー間の相互パスワードベースの認証を可能にします。これにより、スヌーピング攻撃者、またはクライアントまたはサーバーを偽装する攻撃者でさえ、自分で「パスワードを試す」ことができるようなことは何も知ることができません。システム。攻撃者はonline辞書攻撃に制限されています。各パスワードの推測には、クライアントまたはサーバーのいずれかとの相互作用が含まれます。最も知られているPAKEプロトコルは [〜#〜] srp [〜#〜] で、これは SSL/TLS に統合されています。 TLS + SRPを使用すると、証明書がまったくなくても、サーバーとクライアントがパスワードに関して相互に認証される安全なデータトンネルが得られます(これが最も優れた部分です)。おまけとして、サーバーはパスワードをクリアテキストで保存する必要はなく、それから導出された値(それがハッシュされたかのように)のみなので、サーバーデータベースをダンプする攻撃者はパスワードを学習しません(彼は十分に学習し、ただし、オフライン辞書攻撃)。 GnuTLS は、SRPサポート付きのSSL/TLSを実装するライブラリです。

10
Thomas Pornin

これは、一見すると、パスワードテーブルを入手した人なら誰でもユーザーとしてログインできるように思えます。クライアントのステップ1〜4をスキップして、データベースから取得したハッシュを置き換えるだけです。したがって、このシナリオではスキームが非常に弱くなります。

なぜ標準のパスワードハッシュを使用しないのですか? SSL/TLSを使用し、ホワイトリストに照らしてサーバーのフィンガープリントを検証する場合、ほとんどの傍受攻撃はすでに防止されています。

または、偏執狂の場合は [〜#〜] srp [〜#〜] の適切な実装を使用してください。しかし、それ自体を実装しないでください。動作しているように見えても安全ではない、不適切な実装を生成するのは非常に簡単です。

9
CodesInChaos

「あなた自身の暗号システムを設計しようとするのをやめなさい」と言う人々に加わらなければならないでしょう。あなたは十分賢くない。私は十分賢くない。あなたが問題に取り組むのに10年を費やしていないなら、あなたはそれを行うことができません。

なぜ最大長があるのですか?とにかく、常にハッシュします。必要に応じて100万文字のパスワードを設定します。100万バイトのパスワードではなく、32バイトの最終ハッシュのみを保存するため、問題はありません。

パスフレーズが好きな人もいます。パスフレーズは、100文字の長文になる場合があります。特殊文字を含む複雑なパスワードよりも速く、フレーズを使用して100文字のパスワードを入力できます。

ユーザー名に基づいてソルトを作成しないでください。完全にランダムな情報を使用し、ユーザーがパスワードを変更するたびに新しいソルトを生成します。そうしないと、ハッカーがユーザーの大きな辞書を事前に計算し、ユーザーがパスワードを変更した場合でも、アカウントを繰り返しハッキングする可能性があります。

可能な限り最も安全なハッシュ関数を選択するという観点から考えているようです。そのようなアプリケーションでは、特にキー強化を使用する場合、SHA-512はMD5よりも安全ではないのが現実です。 MD5を1000回繰り返すことは、SHA-512よりもはるかに安全です。セキュリティはトレードオフです。クライアントで最も簡単に実行できるハッシュアルゴリズムを選択します。これは、SHA-1またはSHA-256である可能性が高く、「最も安全」な方法ではありません。

SSLにはすでにリプレイ保護があります。なぜ自分で認証システムを複雑にするのですか?ただし、SSLのため、クロックがずれすぎていないことが保証されます(そうでない場合、SSLは失敗します)。

単純なMD5ハッシュを使用するなど、すべてを間違えたとしても、ハッカーはサイトのパスワードの50%以上を解読することはできません。逆に、すべてを正しく行うと、ハッカーはわずかに変更された辞書ハックを介してパスワードの20%をクラックすることができます。データベースが危険にさらされている場合でも、何をしても、一部のパスワードが解読されるのを防ぐことはできません。代わりに、あなたの目標は、ソルトを使用したPBKDF2やキー強化など、ハッキングを最小限に抑えるための標準的なことを行うことです。

さらに、これにどれほどの時間を費やしても、クリアテキストでセッションCookieを送信するなど、他の一般的な間違いをする可能性があります。

最終的に、私が言おうとしていることは、独自の暗号化システムを設計するのをやめることです。あなたはそれを本当に理解せずに愚かなミーム「曖昧さはセキュリティではない」を繰り返しますが、あなた自身の暗号システムを設計しようとするのをやめるという一般的なアドバイスに従うことを拒否します。

5

あなたがこのスキームで達成しようとしていることは、よく知られており、実績のある方法ではすでに達成できないことはわかりません。

まず、クライアントの時間に依存することはできません。多くの人は自分の時計を同期させず、タイムゾーンを考慮する必要があります。

第2に、攻撃者は指摘されたようにブルートフォースを実行したいだけ何度でも認証スキームを通過できます。ロックアウト機能を追加できますが、それを任意のスキームに追加できます。

3番目に、スキームは認証POSTの再生を防ぎますが、時間を使用しますが、これは同期の問題のために悪い考えです。より良いアイデアは、新鮮さを保証するために広く受け入れられているメカニズムであるチャレンジ/レスポンスです。

ハッシュにチャレンジトークンを含めた場合、インターセプトされたハッシュは1分間アクセスを提供しません。これは1回しか使用できません。

認証に不安があり、SSLを信頼したくない場合は、2要素認証を実装することをお勧めします。チャレンジ/レスポンスをソルトハッシュやストレッチハッシュと組み合わせて使用​​すると、再生やオフラインでのクラッキングを防ぐことができます。

5
chris

クライアント側からのブルートフォースの強制がいかに困難になるかはわかりません。私はあなたのアプリケーションにユーザー名/パスワードのリストを渡すまで自動化することができます。私がデータベースにアクセスした場合、Rainbowテーブルでのブルートフォースパスワードの強制はほとんど不可能になります(それが、保護しようとしていることを意味する場合)。ただし、ソルトをユーザー名+ハッシュされたパスワードで保存する必要があります(おそらく私はハッシュスキームをリバースエンジニアリングすることができます)。したがって、特定のユーザーをターゲットにしている場合は、データベースの1つのエントリに対してRainbowテーブルを生成できます。 1つのアカウントのみが必要でした。

クライアント側のブルートフォースの防止については、試行が失敗した後にログインにタイムロックをかけることができます。試行が失敗するたびに、ユーザーは2 ^(失敗した試行)秒待ってから、別のログインを試行できます。これは、クライアント側とサーバー側で実施する必要があります。また、悪意のあるユーザーがあなたのスキームを別のユーザーのDoSとしてどのように使用することができるかについても考えてください。

3
Petey B

私はそれが他のどこにも言及されていないので、ここで言及します:あなたの塩は特に安全ではありません。ソルトの(唯一の)ポイントは、レインボーテーブルのような事前計算攻撃を非実用的にすることです。これは、ソルトを推測する方法がなく、可能な値の範囲が広い場合に最も効果的に達成されます。

ユーザー名を使用することで、同じユーザーとパスワードの組み合わせが常に同じハッシュを持つようになります。一般的なユーザー名のセットは限られているため、攻撃者はそれらのユーザー名のハッシュを事前に計算できます。一般的なユーザー名の数に必要な労力を掛けましたが、それは難しいことではありません。標準的な方法であるランダムなソルトを使用すると、はるかに大きな乗数が導入されます。

最後に、「独自の暗号システムを発明しないでください」という旅団用のプラグをもう1つ追加します。トーマスの優れた答えが示すように、あなたがやろうとしていることを実行する十分にテストされたシステムはすでに存在しています。それらの1つを使用して、自分で発明しないでください。

2
Nick Johnson

パスワードをハッシュするポイントを逃したようです。パスワードをハッシュ化するポイントは次のとおりです。

1)サーバーはハッシュされたパスワードのみを保存します。

2)ユーザーは、ハッシュされていないパスワードをサーバーに提供する必要があります。

3)したがって、サーバーからパスワードデータベースを盗む誰かは、ブルートフォースでパスワードを強制しない限り、サーバーに何を与えるべきかわかりません。

これを実行しました:

1)サーバーはハッシュされたパスワードのみを保存します。

2)ユーザーは、ハッシュされたパスワードをサーバーに提供します。

3)したがって、サーバーからパスワードデータベースを盗む人は、自分のパスワードがどれほど優れているかに関係なく、すべてのユーザーになりすますことができます。

サーバーとクライアントのアルゴリズムを評価するために、「パスワード」はサーバーへの認証に成功するために必要な最小限の情報です。したがって、アルゴリズムの場合、「パスワード」はステップ4で作成されたハッシュのハッシュであり、それがまさにサーバーに格納されているものです。したがって、ハッシュ化/暗号化されていないパスワードを保存します。それは良いことではありません。

1
David Schwartz

総当たり攻撃はほぼ不可能に思われますが、回避策として最も速い方法は、サーバーに送信されたデータ(ハッシュ化されたユーザー名、パスワード、日時)を示し、これをサーバーへの新しいリクエストで使用するtcpスニファです。

サーバーがクライアントからの日付スタンプをチェックして、「古い」かどうかが1分でないかどうかをチェックする場合、クライアントは毎分認証する必要があります。これを検出するために、tcpスニファを引き続き使用できます。

このSSLを回避することが解決策となる場合があります。

0
Thomas