私はこの古い質問をするために私に投げかけられるトマトを持っていると思いますが、ここに行きます。
既存のハッシュ関数から自分のパスワードハッシュを調理することを読んだ後は危険です over および over 繰り返しますが、ロジックはまだわかりません。ここではいくつかの例を示します。
md5(md5(salt) + bcrypt(password))
scrypt(bcrypt(password + salt))
sha1(md5(scrypt(password + md5(salt))))
これらに対する一般的な議論は次のとおりです。
あなたは暗号学者ではありません!これらのハッシュの方が安全かどうかはわかりません。何をしているのかを知っている専門家に任せてください。これらは追加のセキュリティを追加しません。
それらがハッシュとして関数を改善しないことを認める(すなわち、衝突を元に戻したり見つけたりするのをより困難にするなど)が、確実に確実に彼らはそれをハッシュとして作成しませんもっと悪い?そうした場合、ハッカーは標準的にハッシュされたパスワードをこれらの奇抜なハッシュに再ハッシュしてハッシュを弱めることができるでしょうか?買わない。
2番目の引数:
ケルコフの原理 :システムに関するすべてがわかっている場合でも、暗号システムは安全である必要があります。
同意した。これは基本的に、そもそもパスワードをプレーンテキストとして保存しない動機です。しかし、最初の批判に対する私の応答が成功した場合、これらの奇抜なハッシュはまだ安全なハッシュとして機能し、私たちのシステムはそれ以上にケルコフの原理を破ることはありません標準のハッシュで。
ここに、通常のハッシュよりも「奇抜な」ハッシュを使用することの2つの可能な(そして私が見る限りでは価値のある)利点があります。
BCrypt
は安全で、CPUとGPUにとって難しいと考えられています(素晴らしい) 専用ハードウェアで非常に高速にできる 。 SCrypt
は、CPU、GPU、および現時点で特化したハードウェアでブルートフォースを実行するのは難しいと言われていますが、BCryptほど露出度が低いため、暗号化コミュニティからは信頼されていません。しかし、ハッシュBCrypt(SCrypt(password + salt))
は両方の世界で最高のものを得ませんか?これらの自家製のハッシュに対するほとんどの怒りの背後にある情熱/怒りは、平均的なプログラマーが良いハッシュを作るものについての知識の欠如から来ており、この種の奇抜なハッシュを奨励することは必然的に弱くて役に立たなくなるという心配があることに感謝します生産コードに入るハッシュ。しかし、奇抜なハッシュが堅固で信頼できるハッシュから注意深く構築されている場合、セキュリティの向上はあまり価値がなく現実的ではありませんか?
私はこれについてたくさんの良い答えを得ました、ありがとう。私の仮定で見落としているように見えたのは、ハッシュを組み合わせると元のパスワードを簡単にクラックできず、構成ハッシュをクラックすることができないということです。より安全なハッシュは、少なくとも原則として、それらの間の研究されていない複雑な相互作用により、その内部ハッシュのどれよりも弱い可能性があります。つまり、必ずしも奇妙なハッシュを通過したsome文字列を、それを構成するハッシュを壊すことなく見つけることができるということです。
あなたがこの質問をする必要があるという事実は答えそのものです-これらのプリミティブをスタックすることの何が問題なのかわからないので、おそらくどんな利点または弱点があるかを知っています。
あなたが与えたそれぞれの例についていくつか分析してみましょう:
md5(md5(salt) + bcrypt(password))
ここにいくつかの問題があります。最初はあなたが塩をMD5化しているということです。これにはどのようなメリットがありますか?無し。これにより複雑さが増し、ソルトはパスワードの衝突や事前計算(例:レインボーテーブル)攻撃を防ぐために一意であることを単に意味します。ここでMD5を使用しても意味がありません。MD5には些細な衝突が知られているため、実際にはスキームを弱める可能性があります。そのため、ここでMD5を導入すると、2つの一意のソルトが同じMD5ハッシュを生成して、ソルトが効果的に複製される可能性があるという小さな可能性があります。それは良くないね。
次に、パスワードにbcryptを使用します。 OK。まあ、ほとんどのbcrypt実装は内部的にソルトを必要とするので、これはすでに技術的に無効です。あなたがそれを知っていて、bcrypt(md5(salt), password)
を言うつもりだったとしましょう。この部分は、私が上記で説明した弱点にまだ落ちていますが、それほど粗末ではありません-MD5を削除すると、bcryptの標準的な使用法になります。
最後に、あなたはMD5全体です。なぜあなたはこれをやっている?目的は何ですか?どんなメリットがありますか?私が見る限り、利益はまったくありません。不利益な面では、複雑さが増します。ほとんどのbcrypt実装は_$2a$rounds$salt$hash
_表記を使用するため、ハッシュ部分を抽出して残りを個別に保存できるように、それを解析するコードを記述する必要があります。また、MD5実装も必要になりますが、これは不要でした。
したがって、潜在的な攻撃ベクトルのコードフットプリントの観点から、単純なbcrypt実装から、カスタム解析コードを使用したbcrypt実装、MD5実装、およびすべてをまとめるためのいくつかのグルーコードに移行しました。利益がゼロで、ソルト処理に潜在的な脆弱性がある。
次の:
scrypt(bcrypt(password + salt))
これも悪くありませんが、bcrypt
の結果をハッシュとソルト/ラウンドカウントに個別に解析するためのコードが必要です。この場合、bcryptとscryptはほぼ同じように異なる方法で機能するため、少しメリットがあると推測します目標は、非常に資金のある攻撃者がカスタムASICを構築してスキームを破るのを少し難しくします。しかし、それは本当に必要ですか?あなたは本当に国民国家があなたのハッシュを壊すためだけに数百万ドルを費やすという状況にぶつかるつもりですか?また、そのようなケースが発生した場合、チップ数を2倍にするために数百万ドルを費やす必要があるのは本当に攻撃者にとって煩わしいでしょうか。
このようにbcryptとscryptを組み合わせる場合のもう1つの潜在的な問題は、2つがどのように相互作用するかについてほとんど研究されていないことです。そのため、問題を引き起こす可能性のある奇妙なケースがあるかどうかはわかりません。より明白な例として、ワンタイムパッドを取り上げます。一部のメッセージm
および同等に長い完全にランダムなキーk
について_c=m^k
_を計算し、完全なセキュリティを取得します。安全性を高めるために、twiceを実行しましょう!これで_c=m^k^k
_...が得られます。まあ、ちょっと待ってください。m
が得られます。したがって、システムの内部がどのように機能するかを適切に理解するために時間をかけなかったため、実際のセキュリティの脆弱性が生じました。明らかに、KDFの場合はより複雑ですが、同じ原理が適用されます。
そして最後に:
sha1(md5(scrypt(password + md5(salt))))
ここでも、MD5のソルト問題が発生しています。 MD5のSHA1ハッシュにも興味をそそられます。 scryptのような低速のKDFをすでに使用している場合、どのような利点がありますか?これらのハッシュを計算するのにかかる数ナノ秒は、パスワードの暗号ダイジェストを計算するのにかかる数百ミリ秒と比較すると見劣りします。あなたは絶対に無関係な「セキュリティ」の層に複雑さを加えていますが、これは常に悪いことです。記述するコードのすべての行は潜在的な脆弱性です。
さて、私が私の答えの最初に述べたその点を思い出してください。この回答のいずれかの時点で「ああそうだ、私はそれについて考えていなかった」と思っていれば、私の主張は証明されています。
あなたは私が Dave の偽の格言として説明するものに遭遇しています:
暗号化機能を追加すると、より安全になります。
これは開発者の間で共通の特徴であり、私もかつてそれを信じていました。 Kerckhoff's Principle などの他の原則の否定と密接に関連しています。結局のところ、あいまいさは安全レールではないことを認識して受け入れる必要があります。それは弱い暗号のための松葉杖です。あなたの暗号が強力であれば、松葉杖は必要ありません。
暗号プリミティブは安全に積み重ねることができ、プリミティブの弱点とそれらの弱点がどのように相互作用するかを理解するのに十分なプリミティブを知っている場合にのみ、セキュリティを向上させます。それらを知らない、または詳細を理解していない場合-まあ、それはあなたが得る方法です Daveのプロトコル 。
問題は、特定の組み合わせが安全かどうかを判断するのに十分なほどよく知っている人がほとんどいないことです。これが、公開されてレビューされるものである必要がある理由です。レビューされていない場合、scrypt
と同等か、CRC32に近いかどうかを知る方法はありません。
したがって、あなたがエキスパートでない場合、あなたが使用した最も弱いプリミティブ(Daveのプロトコルを参照)よりも弱いものがあり、それを知らない可能性があります。または、少なくともそれが解読されるまでは、それを知ることはできません。Pastebinでユーザーのパスワードを見つけることは、スキームに欠陥があると判断するための理想的な方法ではありません。
ある程度のあいまいさが防御の深さの観点から役立つことには同意しますが、基礎となるシステムは安全でなければなりません。
scrypt
、bcrypt
とPBDKF2
の間-少なくとも1つは、ほぼすべてのプラットフォームでサポートされます。これらは既知であり、十分にテストされています。保護レベルは異なりますが、md5
とsha1
の奇妙なスタックよりもはるかに安全です。
Scryptとbcryptの組み合わせに関する特定の質問については、これらの関数には構成可能なコストがあり、特定の用途に耐えられるように維持しながら、そのコストを可能な限り引き上げたいことを覚えておいてください。たとえば、最大[〜#〜] x [〜#〜]の反復でbcryptを使用できる場合(それを超えると、サーバーと1秒あたりのユーザー接続の平均数)、または最大[〜#〜] y [〜#〜]反復のscryptの場合、 [〜#〜] x [〜#〜]でscrypt(bcrypt)をbcrypt then[〜#〜] y [〜#〜]scryptの反復:これはCPUバジェットを超えます。
したがって、scryptとbcryptをカスケード接続する場合は、1つだけで実行するよりも少ない反復で両方を使用する必要があります。単にそれらをひもでつなぐだけでは、「両方の世界のベストを得る」ことはできません。実際、あなたが期待できる最高のものは、2つの間の平均のようなものです。そして、それはより複雑なコードの代償であり、本質的にセキュリティ(または、さらに言えば、保守性)について話すときに悪いものです。
Adamの回答に加えて、暗号化を使用するときはいつでも、それを行うための強力で不可避の理由が必要であることも述べておきたいと思います。上記の例では、これは存在しません。
md5(md5(salt) + bcrypt(password))
scrypt(bcrypt(password + salt))
bcrypt
およびscrypt
アルゴリズムはすでに十分強力であり、事実上壊れないものと見なされています。どのような問題を解決しようとしていますか?そして、なぜそれらの結果を(特にmd5
)解決しますか?最良のシナリオでは、実際にセキュリティを向上させるのではなく、パスワードを解読する難易度を最も弱いハッシュの難易度に減らしただけの可能性があります。そして、最悪のシナリオは恐ろしく未定義です。
md5(sha1(md5(md5(password) + sha1(password + salt)) + password))
このソリューションはさらに悪いです。繰り返しハッシュ方式を手動で実装しますが、実際に攻撃者にかなりの作業要素を課すほど十分なラウンドがありません。
簡単に言えば、問題は次のとおりです。
安全でないアルゴリズムに安全でない操作を適用すると、ハッシュ関数を確実に破ることができます。新しい関数は、最も弱いリンクよりもはるかに悪い可能性があります。
攻撃者がこれを使用して安全な機能を破壊しないのはなぜですか?それは彼らを助けません。たとえば、bcryptを使用して安全に保存されたパスワードの最初の440ビットをゼロで上書きすると、ブルートフォースで一致するパスワードを簡単に見つけることができますが、そのパスワードは自分のひどいアルゴリズムでしか機能しません。健全な実装はおそらくそれを拒否します。
ハッシュの大きなチャンクをゼロにすることは明らかに悪いことですが、安全な操作でさえも危険なものに結合される可能性があります。 2つの数値を加算する(モジュロnで一定の長さを確保する)ことは「安全」です。通常、エントロピーは失われません。それでも、h(x)+ h(x) mod nはハッシュの品質を低下させますh(x)は1ビット、結果は常に偶数です。等しく安全な演算子XORはh(x)XOR h(x) =常にゼロを返します。
これらの落とし穴はかなり明白ですが、すべてがそうであるとは限りません。いつものように、自分で弱点を見つけられないほど十分に優れたスキームを考案することは簡単ですが、他の誰もできないところを考案することは非常に困難です。
ハッシュ関数は暗号技術者によって作成され、暗号技術者によって破棄されます。多くの強力なハッシュ関数と、現在も使用されている弱いハッシュ関数があります。プログラマーは暗号学者とハッシュ関数を信頼するべきです。ハッシュ関数に脆弱性があったとしても、インターネットや同僚を通じてきっとそれが聞こえ、暗号学者はきっと詳細な調査をするでしょう。安全なハッシュアルゴリズムを使用すると、ブルートフォース攻撃が弱点になる可能性があることがわかっています。
ハッシュ関数を組み合わせると、追加のセキュリティはほとんど追加されず、追加したいものは何でも、おそらくすでに関数に実装されています。
パスワードをソルトすることは、レインボーテーブルに対する有効性を減らし、パスワードを単に「検索」することができないようにするのに最適です。関数を2回ハッシュする場合でも、ハッシュ関数を変更する場合でも、基本的にはパスワードをソルトします。そして、ほとんどの関数にはソルトする簡単なメソッドが含まれているため、これを実装する必要はありません。
誰もがそれを行うので、私は自分の安全なハッシュを作成したいとしましょう。そして、私は暗号学者ではないので、「本当に」安全にする必要があります。もちろん、すべてのプログラマーは、すでに作成された安全なハッシュを使用する代わりに、安全なハッシュを作成する方法を知っています。そこで、私は自分の不正なハッシュ関数mod10(md5(sha1(bcrypt(password + salt))))を作成します。
私のハッシュ関数からわかるように、私は非常に多くの異なるものを使用しているので、それは本当に安全です。もちろん、このばかげた例では、10個の異なる可能な出力しかないことが簡単にわかります。ただし、単一の安全なハッシュ関数を使用するだけで、これは完全に回避されます。
確かに、攻撃者がソースコードを持っている場合、システムはセキュリティで保護されている必要がありますが、攻撃者がソースコードにアクセスできず、奇抜なハッシュを推測できず、総当たりを試みる可能性が非常に高いです。無理な力
したがって、攻撃者がハッシュを含むデータベーステーブルを入手したと想定しています。攻撃者がWebページファイルも取得できる可能性が非常に高いと思います。これらのサービスを実行しているシステムは、データベースの取得を可能にしたのと同じエクスプロイトです。データベースサーバーは、そのパブリックが直接アクセスできないように設定されています。一方、コードを含むWebサーバーは最前線にあります。
アルゴリズムの複雑さを増したり、コード行を追加したりするたびに、アプリケーションの障害ポイントが増加します。アルゴリズムを組み合わせると、意図しない結果が生じる可能性があります。これにより、特定のtellsまたは他の兆候が発生し、実際にシステムの暗号強度が低下する可能性があります。
アプリケーションで使用するライブラリが多いほど、アプリケーション全体のリスクが高くなります。脆弱性、コード実行などを可能にする欠陥が1つの実装に見つかった場合、アプリケーションは脆弱です。運が悪ければ、攻撃されなかった別のアルゴリズムを選択した場合、当面は安全です(もちろん運の不運な側面にいる可能性もあります)。
[〜#〜] kiss [〜#〜]:シンプルに保つ、愚か を忘れないでください。複雑さで。
私よりも賢く、セキュリティの経験が豊富な多くの人々に反対します。だから私はおそらく間違っています。
あなた自身のハッシュ関数を即興にすることは良い考えです-あなたがそれを正しく行うなら。次の3つの簡単な手順に従ってください。
ステップ3を完了すると、即席のハッシュ関数を使用しないのはばかになります。
次のハッシュアルゴリズムを適用する前にソルトバックを適用することが重要であることを心配しているため、異なるハッシュ関数を連結する場合、いずれかのアルゴリズムの衝突の弱点によって、使用している2番目のハッシュ関数が損なわれることはありません。
scrypt(bcrypt(パスワード+ salt)+ salt)
しかし、今ではscryptは確立された手法であると思います。Argon2iはパスワードハッシュの競争に勝っており、より安全であると考えられており、bcryptは長い間存在し、簡単なバイパスに対して安全であることが証明されています。
したがって、以下はより意味があり、argon 2iの強度を組み合わせますが、将来の攻撃者がアルゴン2iを簡単に破壊する方法を示した場合、bcryptにフォールバックします。
bcrypt(Argon2i(パスワード+ソルト)+ソルト)
ただし、次のようにすると、間違いを犯す可能性が低くなります。
scrypt(password + salt)またはbcrypt(password + salt)
ほとんどの違反はコードの人為的エラーが原因であることに注意してください。SQLインジェクション攻撃が通過しないことを確認するために、コードを単純に保ち、動的、静的分析および人のコードレビューアーでコードを徹底的にレビューする方がはるかに優れています(データベースクエリを常にパラメーター化することを忘れないでください) !)