パスワードを安全に保存するためのHMACまたはbcryptまたはscryptライブラリのどちらを選択するかを選択します。
パスワードハッシュの計算の問題と微妙さ、およびHMACがこの問題に適さない理由を適切に理解するために、質問に直接答えるのに実際に必要なよりもはるかに広い答えを提供します。
HMACハッシュアルゴリズムは、本質的に、通常のハッシュアルゴリズムのキー付きバージョンです。通常、整合性と信頼性を検証するために使用されます。これの通常の表記はH(m,k) = h
です。ここで、H
はHMACハッシュアルゴリズム、m
はメッセージ、k
はキー、h
は結果のハッシュです。秘密はk
を共有する2つの当事者が、相手がm
の作成者であることを確認できるという考え方です。さらに、攻撃者はk
を知らずにメッセージハッシュを偽造することはできません。
これは次のように行われます。
k
を知っています。m
を書き込み、k
、つまりH(m,k) = h
を使用してメッセージのHMACハッシュを計算します。m
とハッシュh
をボブに送信します。H(m,k)
を計算し、それをアリスが送信したハッシュh
と比較します。ハッシュが一致した場合、アリスはメッセージを送信したこと、およびアリスがハッシュした後にメッセージが変更されていないことを知っています。HMACが何であるかを理解したところで、本当にしたいこと、つまりデータベースにパスワードを保存することに移りましょう。
何年も前は、パスワードをプレーンテキストでデータベースに保存するのが標準的な方法でした。データベースが危険にさらされると、攻撃者がすべてのパスワードを入手したため、これは悪い考えでした。これに対処するために、一方向暗号化ハッシュアルゴリズムを使用してデータベース内のパスワードのハッシュを開始しました。 MD5は人気が出ましたが、弱点(衝突、部分的な前イメージなど)が発見されたため、MD5は推奨されなくなりました。多くの人々がより安全なSHA1に移行しました。
このアプローチの問題は、ハッシュとそれに対応する平文の巨大なテーブルを作成できることです。これらは Rainbow tables と呼ばれます。彼らは、考えられるすべてのパスワード(特定のセット内)のハッシュの膨大なリストを計算して保存する方が効率的であり、後ですばやく照会できるという概念に取り組んでいます。そのため、個別のハッシュを総当たりにする代わりに、データベースにハッシュを照会するだけで、プレーンテキストをすぐに返すことが可能になりました。
これを修正するために、セキュリティオタクは塩を発明しました。ソルトは、ハッシュされる前にパスワードに付加される大きな一意のランダム値です。このソルトはハッシュとともに保存されるため、後で再び計算できます。したがって、H(m+s) = h
を計算し、h
とs
をデータベースに格納します。これは、重要な Rainbowテーブルに対する保護 を提供します。これは、ソルトごとに個別のRainbowテーブルを生成する必要があるためです。
そのため、悪者は辞書攻撃と総当たり攻撃に切り替えました。 GPUコンピューティングの登場により、適度に強力なグラフィックスカードで毎秒数十億のハッシュを計算できるようになりました。実際、人々はほぼ 500億回のMD5ハッシュ/秒 を計算できるコンピュータを構築してきました。 GPUがこれを実行できる理由は、GPUが膨大な数の並列スカラー演算を実行するように設計されているためです。スカラー演算は、分岐を含まない数学演算と論理演算です。つまり、「xの場合はyを実行する」などの多くの処理を行う必要はありません。暗号化ハッシュアルゴリズムは、このモデルに適合する傾向があります。
これを困難にするには、ブルートフォースを実行できないようにハッシュ操作を遅くする必要があります。通常のハッシュアルゴリズム(SHA1など)は高速になるように設計されているため、この目的には適していません。 HMACはオーバーヘッドをほとんど追加せず、追加のセキュリティマージンもないため、ここでもあまり使用されません。
遅い暗号化ハッシュアルゴリズムを作成することは、言うよりも簡単です。低速で、還元不可能(つまり、現在の状態を超えて最適化できない)で安全なアルゴリズムを思いつくことは非常に困難です。これを行うことができる3つの一般的なハッシュ関数があります: PBKDF2 、 bcrypt 、および scrypt 。これらは、平文およびソルトとともに作業係数値を受け入れるため、適応鍵導出関数として知られています。作業係数は、ハッシュの計算にかかる時間を変更し、将来のハードウェアの改善から保護するように設計されています。
したがって、適応鍵導出アルゴリズムH
の場合、H(m,s,w) = h
を計算します。ここで、m
はメッセージ(パスワード)、s
はソルト、 w
は作業係数です。結果のh
には通常s
とw
が含まれるため、検証関数は後で同じパラメーターを使用して同じハッシュを計算できます。一般に、作業係数は、内部暗号プリミティブの実行される反復回数を制御します。目標は、クラッキングを実行不可能にするのに十分な時間を計算にかけることですが、私たちが持っているリソースを超えないようにすることです。
専用のハードウェアベースのクラッキングに対するセキュリティを強化するために、scryptはハッシュ計算がCPUハードとメモリハードの両方であることを保証します。つまり、ハッシュ値を生成するためにかなりのCPUとメモリリソースを必要とします。 FPGAs は通常、即時メモリにほとんどアクセスできないため、これは重要です。
さて、明らかな疑問が生じます。bcryptを使用するようにサイトを設定した場合、それはサーバーがCPUを集中的に使用するハッシュを常に計算しなければならないことを意味しませんか?まあ、あなたがあなたのサーバーでそれらを実行するなら、そうです、それは考慮に入れるべきものです。 より良い解決策は、クライアントにハッシュを計算させ、それをSSL経由でサーバーに送信することです。サーバーはそれをデータベースの値と比較できます。これにより、(データベースの侵害などにより)パスワードハッシュが盗まれた場合でも簡単にクラックされず、サーバーがパスワードハッシュ計算のオーバーヘッドに圧倒されないことが保証されます。 Webサイトの場合は、 jsBcrypt を使用できます。 更新:このメソッドは、以下のコメント投稿者から欠陥があると指摘されています。使用しないでください。
うまくいけば、これで状況の概要がわかり、HMACがこの種の使用に適さない理由がわかります。
HMACは非常に高速になるように設計されており、このコンテキストでは、単に追加するのではなく、パスワードにソルトを追加するための良い方法です。初期化が遅いため、Bcryptははるかに遅くなりますが、scryptは意図的にそのように設計されているため、Bcryptよりもさらに遅くなります。 Scryptはブルートフォースを非常に計算コストの高いものにするように設計されています。 CPUとメモリを大量に消費し、GPUでの使用も低速です。