web-dev-qa-db-ja.com

何を転送しますか?パスワードまたはそのハッシュ?

私のデータベースに、かなり高価なハッシュ(scrypt、SHA2の1000ラウンドなど)を使用してソルトでハッシュされたパスワードを保存するとします。

ログイン時に、ネットワーク経由で何を転送する必要がありますか。その理由は何ですか。パスワードまたはそのハッシュ?

HTTPのような暗号化されていないチャネルを介してそのようなログインを保護することは可能ですか?

40
Konrad Garus

クライアントからハッシュを転送する場合、これはセキュリティ上の利点がなく、ハッシュは無意味になります。
ユーザーがハッシュをサーバーに送信してログインできる場合、ハッシュは事実上パスワードです。

61
AviD

認証プロトコルがサーバーにパスワードまたはパスワードのハッシュをプレーンHTTPで送信する場合、次の2つの理由から、これは本質的に非常に脆弱です。

  • 回線をスパイしている誰かが、クライアントが送信したものを記録する可能性があります。これらのバイトを送信するだけでアクセスが許可される場合、攻撃者は単にそれらを再度送信する可能性があります。 リプレイ攻撃 です。この問題は、@ AviDが彼の回答でほのめかしているものです。ハッシュの量はそれを修正しません。一部のプロトコルは、サーバーからの "チャレンジ"(接続ごとに新しく作成されたランダムな値)をクライアントのパスワードと一緒にハッシュすることで、この問題を修正しようとします。それが HTTPダイジェスト認証 の意味です。

  • 認証が機能しても、これはプレーンHTTPであるため、送信されるデータafterwardsは、攻撃者による盗聴や改ざんに対して脆弱です。トランスポートメディアが保護されていない場合、認証は最も洗練されていない攻撃者のみを阻止します。ここでHTTPダイジェストが失敗します。

したがって、パスワード(またはそのハッシュ)を伝達するだけでなく、クライアントとサーバー間の会話の残りの部分も伝えるために、SSL(別名HTTPS)が本当に必要です 。


これ以降、プロトコルはSSLトンネル内で実行されると想定します。 bcryptやPBKDF2のようにslow hashを使用するのは正しいことです。saltもコストの共有を防ぐために必要であることに注意してください(例:事前計算されたテーブル)。パスワードの本質的な弱点に対処するために、低速のソルトハッシュが使用されます。ここで、クライアントのハッシュ作業の一部をオフロードしたい場合があります。これはmay動作しますが、いくつかの実用的な問題を引き起こします:

  • パスワード処理にはソルト(パスワードインスタンスごとに新しいソルト)を含める必要があるため、ソルトをクライアントに伝達して、クライアントが実行するハッシュにソルトを含めることができるようにする必要があります。これにより、プロトコルの複雑さが増します。クライアントは最初にユーザー名をサーバーに送信する必要があり、次にサーバーはソルトを返信する必要があり、クライアントは(その場合のみ)パスワードのハッシュを開始できます。これは、通常の「ユーザー名とパスワードを1つのPOSTリクエストとして送信する」の場合よりも1回多いネットワークラウンドトリップです。

  • 遅いハッシュとは、各パスワードに多くのCPUを費やすことを受け入れることです。そのため、攻撃者はalsoが各パスワードに多くのCPUを費やす必要があります。しかし、使用済みCPUがクライアント上にある場合、1)CPUが非常に少ないクライアント(たとえば、いくつかの安価なスマートフォンまたはタブレット)があり、2)Webコンテキストが意味するため、必要なだけCPUを上げることはできません。 Javascriptを使用しており、ハッシュに関してはJavascriptのパフォーマンスが非常に悪い(たとえば、Cコードより少なくとも20倍遅い)。

そのため通常の知識は、クライアントでパスワードハッシュの一部を作成することは努力に値しないということです。

24
Thomas Pornin

どちらのオプションも安全ではありません。

パスワードを転送すると、プロトコルがプレーンテキストになります。ハッシュを転送すると、リプレイ攻撃に対して脆弱になります。

APOPは、POPプロトコルのログイン実装です。これにより、プロトコルはネットワーク上のすべてのリスナーからパスワードを秘密に保つことができます。これの欠点は、これが共有シークレットであるため、クライアントとサーバーの両方がプレーンテキストのパスワードを知っている必要があることです。プロトコルの前は、クライアントとサーバーの両方に<パスワード>があります。プロトコル通信は基本的に次のようになります。

  1. クライアントがサーバーに接続し、ランダムトークン(T1)を送信する
  2. サーバーがランダムトークン(T2)を送信する
  3. クライアントがサーバーにM = sha(T1 + T2 + <パスワード:クライアントのコピー>)を送信する
  4. サーバーは、sha(T1 + T2 + <パスワード:サーバーのコピー>)がM(受信したハッシュ)と一致するかどうかを確認します。

ここでは、サーバーはマジックとパスワードの両方を知っており、リスナーに公開することなく、ユーザーが正しいパスワードを知っているかどうかを判別できます。

ハッシュをデータベースに安全に保存し、暗号化されたチャネルに依存することをお勧めします。

4