私は読んだ 「開発者の自作のパスワードセキュリティは正しいのか、間違っているのか、そしてその理由は何か?」 ですが、私の心にはまだ疑問があります。
だれかがDaveのように自家製のセキュリティアルゴリズムを悪用しても、攻撃者がサーバーではなくデータベースを危険にさらすだけの場合、実際のパスワードを取得することはできません。 マークバーネットの答え デイブの質問への私の推測を証明するようです。
もう一度、Daveのコードを例にとります。 Daveは安全でない/高速なハッシュ関数md5とsha1を使用しているので、データベースから彼のパスワードを解読(プレーンテキストを取得)できます。しかし、彼のサーバーが危険にさらされていなければ、実際のパスワードを取得することはできません。
わかりやすくするには...攻撃者がデータベースにアクセスできるが、アプリケーションのソースコードにはアクセスできない場合のデータベースのみの侵害について説明します。その場合、Daveのカスタムアルゴリズムにより、攻撃者はパスワードハッシュを取得しますが、それらを解読して元のパスワードを取得することはできません。そのため、データベースのみの違反の場合、はい、デイブのパスワードアルゴリズムは、MD5またはSHA1を使用した場合よりもパスワードを保護します。
ただしシステムリークが発生する可能性があるのは1つだけです。 Daveの自作のアルゴリズムが合理的であるように見える「数学」を台無しにする1つの重要な事実があります。
(出典 12 )これは、いったん侵入させてしまうと、非常に冷静な事実になります。従業員による違反の半分は、それらの半分は偶発的であり、半分は意図的です。 Daveのアルゴリズムは、心配するのがデータベースのみのリークだけの場合に役立ちます。それがあなたが心配しているすべてであるなら、あなたがあなたの頭の中で防御している脅威モデルは間違っています。
ほんの一例を挙げれば、開発者は当然、アプリケーションのソースコードにアクセスできます。したがって、開発者が本番データベースへの読み取り専用アクセス権を取得すると、パスワードを簡単に解読するために必要なものがすべて揃います。 Daveのカスタムアルゴリズムは、古くて簡単に解読できるハッシュに依存しているため、今では役に立たなくなりました。
ただし、Daveが最新のパスワードハッシュアルゴリズムを使用し、saltとpepperの両方を使用した場合、データベースのみのダンプにアクセスした開発者はまったく何も役に立ちません。
これはランダムな例の1つにすぎませんが、全体的なポイントは単純です。実際の世界では、Daveのアルゴリズムではできなかった適切なハッシュによって実際の損傷を止めることができたはずのデータリークがたくさんあります。
それはすべて、多層防御についてです。特定の種類の攻撃から保護できるセキュリティ対策を作成するのは簡単です(Daveのアルゴリズムは、データベースのみのリークから保護するためにMD5よりもわずかに改善されています)。ただし、それではシステムが安全になるわけではありません。実際の侵害の多くは非常に複雑であり、システムの複数のポイントの弱点を利用して、最終的にいくつかの実際の被害をもたらします。 「これは私が心配しなければならない唯一の攻撃ベクトル」(これはDaveがしたことです)という仮定で始まるセキュリティ対策は、事態を危険なほどに間違ったものにするでしょう。
これは、Daveのプロトコルに関する質問には特に答えていませんが、自分のハッシュを書いている世界中のDavesのために、より一般的な質問に取り組みたいと思いました。デーブス、あなたが気づく必要のあることがいくつかあります:
そしてそれはすべて、データベースへのオフライン攻撃についてのみ考えているだけであり、サイバーセキュリティを専攻していない大学生によって考えられています。私はかなりの数を逃したことを保証します。 MITMや悪意のあるクライアントなどの他のすべての攻撃ベクトルは完全にスキップしました。また、既製の製品を使用した場合でも発生する可能性のあるすべてのエラーについては省略しました。良い暗号を間違って使用する方法を読者が理解することは、演習だと考えてください。最後に、開発者がencryptionを使用する必要がある一般的なエラーのクラスを完全に省略しましたが、hashを使用する必要があります。たまに見ます。
つまり、デイブ、プロダクションコードに使用する秘密の内部ハッシュについて最高のアイデアを持っていると思うときはいつでも、標準を使用することはではありません 、市販の、徹底的にテストされた製品で、これを覚えておいてください:
Bcryptを使用するだけです。 (または Argon2 )
(余談ですが、楽しみや自己教育のためのアルゴリズムを構築しているだけの場合は、これをすべて無視してください。本番環境でパスワードを保護するために独自のアルゴリズムを構築してください保護をほとんどまたはまったく提供しない弱いアルゴリズムを構築するため、危険です。独自のアルゴリズムを構築して、それを破ることができるかどうかを確認するは、時間を渡す優れた方法です、あなたの心を刺激し、おそらくいくつかの暗号を学ぶことさえできます。)
ソースコードではなくデータベースの違反の場合、Davemightはに比べて状況を改善しましたプレーンSHA1。だが...
Conor Manconeが説明する のように、ソースコードもリークされる可能性があります。
自作はハッシュをめちゃくちゃにして、単純なSHA1よりも安全性を低下させる可能性があります。神は、デーブスの奇妙な仕掛けがハッシュアルゴリズムの内部とどのように相互作用するかを知っています。他に何もない場合、デイブは彼の後に来る人々のために少し保守の地獄を作りました、そして大きな混乱は決してセキュリティに良いことではありません。
それは誤った安心感を与えます。デイブが彼の素晴らしい解決策をそれほど誇りに思っていなかったなら、彼はパスワードハッシュを正しく行う方法を読むのに時間をかけたかもしれません。質問から、デイブは彼がやったことはbcryptと言うよりも良いと思っていることは明らかです。そうではない。
自作のアルゴリズムによって提供される少し余分な保護は、代わりにコショウで達成できたでしょう。可能な限り、自作のアルゴリズムよりも優れています。
ですから、非常に特殊な状況では、自作のほうがSHA1よりも優れている場合があります。平均してそれが良いかどうかは未解決の質問ですが、答えはそれほど重要ではありません。ポイントは、実際のパスワードハッシュアルゴリズムと比較してひどいことであり、それがまさにホームブリューによってDaveが実装できなくなったということです。
要するに、デイブはこれを犯した。
TLDR:暗号化された値が表示されない場合、安全でない暗号化は安全ではありません。
他の投稿は、攻撃者が暗号化された値を見ることができる環境で、独自の暗号化を記述すべきではない多くの理由を説明するのにかなり優れていますが、本当に重要なものを見落としています:また、攻撃者が暗号化されたメッセージを見ることができない場合は、独自の暗号を記述しないでください。
これは「サイドチャネル」と呼ばれるものです。サイドチャネルは(通常は1)アプリケーションが何をしているかについての情報をリークする意図しないこと。たとえば、「暗号化された」パスワードと部分的に正しいパスワードを比較するには、より多くのCPUサイクルが必要になるため、時間がかかります。2 値。これにより、攻撃者はブルートフォース攻撃を加速し、正しいパスワードをゆっくりと学習できるようになります。
単純な例を見てみましょう。送信されたパスワードの1文字をデータベースに保存されている値と照合するのに1秒かかるとしましょう。正しいパスワードが8文字であると想定し、無効なパスワードは最初の不正な結果で拒否されます。アルゴリズムは次のようになります。
boolean encrypt_password(string password) {
if(not isascii(password) ) { return false; } // ERROR!
string result;
foreach(char c : password) {
result += daves_magic_that_takes_1s(c)
}
return true;
}
boolean is_correct_password(input, pw_from_db) {
if(input.length != pw_from_db.length) { return false }
foreach(char c_in, c_db : input, password) {
c_in = daves_magic_that_takes_1s(c_in)
if(c_in != c_db){ return false}
}
return true; // valid password!
}
ここで、有効なパスワードが「password」であり、攻撃者が入力「a」を試行するとします。パスワードの長さが間違っているため、これは失敗します。攻撃者はランダムにさまざまなパスワードを試す可能性があります。 「password」よりも長いまたは短いすべての誤ったパスワードは、処理に1秒未満かかります。彼らがすぐに「12345678」を試してみるとしましょう。 「12345678」は「パスワード」と同じ長さなので、処理に1秒かかります。タイミングが異なり、攻撃者が気づく。彼らはさらに数回検証を試み、それは一貫しています。
攻撃者は現在、8文字のパスワードをいくつか試します。彼らはすべて1秒かかります。攻撃者は、有効なパスワードがおそらく8文字であることを知らせるサイドチャネルを発見しました。次に、どの8文字のパスワードが正しいかを判断する必要があります。
攻撃者はランダムに8文字のパスワードを試し始めます。最終的に、彼らは「p2345678」を試し、これが完了するまでに2秒かかることに気付きました。彼らはたくさんをテストし、「p」で始まるすべての試行が完了するまでに2秒かかることを発見しました。攻撃者は、アルゴリズムにサイドチャネルがあり、正しい文字数を知らせると推測します。
これで、有効なパスワードを総当たりするためにすべての96 ^ 8個のパスワードを試行する必要はなく、攻撃者は96 * 8個のパスワードを試すだけで済みます。3。並行してテストできるパスワードの数によっては、非常に妥当な時間内にパスワードをブルートフォースで正常に実行できる可能性があります。これは攻撃者にとって素晴らしいことです。そしてそれはあなたのシステムのセキュリティのためにひどいです。4
タイミングサイドチャネルからどのように保護しますか?タイミングによって機密情報が漏洩するすべての操作の実行には、常に同じ時間がかかることを保証します。
これは非常に単純な例のように見えるかもしれません。それは野生で起こりました。 NVDで「タイミングサイドチャネル」を検索すると、同じ種類の結果を生み出す多くの現実世界の脆弱性が得られ、攻撃者は許可されていない秘密情報を知ることができます。定義により、入力に関係なくすべての操作に同じ時間がかかる場合、何かにかかる時間は入力について何も伝えません。
現実の世界では、サイドチャネルの導入は非常に簡単です。デイブはおそらくそれらについて聞いたこともないでしょうし、おそらく彼のシステムのパフォーマンスに関心のある優れたエンジニアでしょう-これは実際にはサイドチャネルから保護するためのアンチパターンです。デイブのアルゴリズムには、彼が決して発見することのない明白で微妙なサイドチャネルが含まれている可能性がありますが、その研究者と attackers は探すことを知っており、自動テストを簡単に作成して検出できます。5
したがって、暗号を確認できないからといって、不正な暗号の副作用を確認できないというわけではなく、それらの副作用を使用して保護された秘密を知ることができます。
文末脚注
1:まあ、もしあなたが諜報機関や優れた新聞ジャーナリストなら、おそらく「敵」が知らなくてもエージェント/情報源と通信できるように意図的にサイドチャネルを設定しているでしょう。同様に、あなたが欺瞞的であるなら、あなたは秘密の情報を漏らすことを意図して、その中にサイドチャネルを持つ暗号プロトコルを作成するかもしれません。
2:カスタム暗号は安全ではないと常に想定できるため(他の人がこのスレッドで言及した理由などにより)、おそらくカスタム暗号アルゴリズムの使用を「暗号化」または「復号化」と呼ぶべきではありません...たぶん「安全でない暗号化」または「壊れた解読」...
3:説明を簡単にするために、攻撃者が50%+ 1個のパスワードを試行した場合、平均して成功する総当たり攻撃は無視します。私はブルートフォース攻撃ではなく、サイドチャネルに焦点を当てています。また、ブルートフォース攻撃の数学についても説明します。これは、メイントピックにも接するためです。読者に代わって一部のGoogle-Fuは、詳細に詳しいリソースをたくさん見つける必要があります。
4:「1秒は遅すぎる」でしょ?実世界のシステムでは、インターネットを介して実世界のタイミングサイドチャネルをチェックできませんでした。違う。手元に参照はありませんが、HTTPトランザクションを介してミリ秒のオーダーでタイミングを統計的にテストできることを示す調査が何年も前からありました。
5実際、Google-Fuを使用する場合、明らかなサイドチャネルについてアプリケーションをテストするために使用できるフレームワークまたは既存のツール(ほとんどは両方)があることは間違いありません。
特定のユーザーのパスワードを知っているとしましょう。さらに良いことに、サインアップして自分のパスワードを何回でも作成できるとしましょう。
そして、あなたはデータベースへの読み取りアクセス権を持っています。
さらに、かなり単純な自作アルゴリズムであると疑っている(またはknow)と仮定します。
この時点で、アルゴリズムの総当たりを開始し、データベースでハッシュを取得することができます。たとえば、アルゴリズムが「推測」される場合があります
$hash = md5($pass . $salt . 'some random string');
ランダムな文字列をブルートフォースにします。文字列が長くなると、これは難しくなりますが、慎重にパスワードを選択することで、md5の弱点を悪用できる可能性があります。
あるいは、アルゴリズムを「推測」することもできます
$hash = sha1(md5($pass . $salt . 'abc') . 'def');
そして、ブルートフォーシングをもう一度試します。
Daveのアルゴリズムと同じくらい複雑なものは、いくつかのヒントがなければ非常に困難です。キャラクターの並べ替えが含まれていることがわかっている場合は、それが役立ちます。
@Conor Manconeの回答と @ Conor Manconeと@Andersで話し合った を読んで、この質問以外にも多くのことを学んだので、書き留めることにしました。もう一度間違えたら訂正してください。
md5
_と_sha1
_は壊れていますが、私がどう思っているかではありません_md5
_と_sha1
_のハッシュ出力は、入力の大きさに関係なく、常に簡単に解読できる(元の入力テキストを取得できる)と誤って考えていました。
いいえ、そうではありません。
サーバーで十分長いペッパーを使用している場合、_md5
_または_sha1
_を使用してパスワードをハッシュしても、サーバーは安全です妥協しない。
たとえば、データベースにmd5($ 128bits_long_pepper . $password)
を保存します。
塩がなくても、割ることはできません。 _md5
_ハッシュ速度が_100 billion hash/s
_であるとしましょう。 _2^40 hash/s
_なので、便宜上_2^40 > 100 billion
_としましょう。それを総当たりにするために、まだ_2^128 / 2^40 = 2^88 seconds = 9.80719764 × 1018 years
_が必要です。そしてもちろん、私はだれもそのようなレインボーテーブルを事前に計算することはないと思います。
しかし、パスワードをハッシュするために_md5
_を選択するとは言いません。私はしません。サーバーも危険にさらされると、ハッシュされたこれらのパスワードはクリアテキストと変わりません。
私は初心者で、_md5
_と_sha1
_がいかに悪いかについて多くの投票が寄せられた投稿を読みましたが、この⬆️についての答えはわかりません。私はコメントでいくつかだけ気づきます。
最後に、これら3つの概念とそれらの使用例/組み合わせを完全に理解したと思います。
最初に、私は3種類の攻撃を自分でまとめます:1.総当たり攻撃(「すべてを試す」方法)2.レインボーテーブル攻撃(直接逆引き参照)3.辞書攻撃(_$pepper. $common_password. $salt
_ブルートフォース、部分的ブルートフォース、_1.
_と比較)
だから私は思う:
例で説明します。
(Salt)多くの人々が説明するように、塩はそれほど大きな問題ではないことを理解する必要があります。これは、攻撃者がレインボーテーブルを逆ルックアップしてハッシュされていないパスワードを取得することはできないことを1つだけ守っています。 _salt + fast hash function
_(サーバーにペッパーなし)のみを使用している場合、攻撃者はハッシュされたパスワードごとにブルートフォースを実行できます。もちろん、もう1つの前提条件は、ユーザーが登録のために_128bit
_長いパスワードを保存する必要がないことです。
そう :
salt + fast hash function
_はブルートフォース攻撃を防御しません。レインボーテーブル攻撃やディクショナリ攻撃を防御できるかどうかは、今のところ重要ではありません。salt + slow hash function
_はブルートフォース攻撃を防御します。また、レインボーテーブルの攻撃も防御します。辞書攻撃を防御しません。(Pepper)ただし、_salt + fast hash function
_の組み合わせでは、サーバーが危険にさらされていなければ、サーバーで十分長いペッパーを使用すると、データベースだけが行う場合でも、パスワードは安全です。
そう :
salt + fast hash function + long pepper(e.g.128bits) + server not compromised
がブルートフォース攻撃を防御できるようになりました。また、レインボーテーブル攻撃や辞書攻撃を防御します。(ハッシュ関数)しかし、サーバーが危険にさらされると、上記の組み合わせはたわごとのようになります。攻撃者はコショウを知っているでしょう。 salt + fast hash function + long pepper(e.g.128bits) + server gets compromised
を解読する難しさは、誰かが_fast hash function
_のみを使用するのと同じです。
そう :
salt + fast hash function + long pepper(e.g.128bits) + server gets compromised
はブルートフォース攻撃を防御しません。レインボーテーブル攻撃やディクショナリ攻撃を防御できるかどうかは、現在重要ではありません。salt + slow hash function + pepper (not necessary to be very long e.g. 6 chars maybe good enough?) + server gets compromised
総当たり攻撃を防御します。また、レインボーテーブルの攻撃も防御します。辞書攻撃を防御しません。_salt + slow hash function
_はどうですか?この組み合わせは、ブルートフォース攻撃とレインボーテーブル攻撃を防御します。しかし、それは辞書攻撃を防御しません。サーバーにコショウを追加するのは簡単ですが、なぜですか?
上記からわかるように、コショウはサーバー側で変換を行うために使用するものです。
サーバーが危険にさらされない限り、本当に重要なのは「サーバーでの変換」です。
例として、ランダムな定数を受け取り、それをパスワードhash($pepper . $password, $salt)
と連結します。これは一種の変換です。そのため、Daveのようにサーバー上でいくつかのくだらないアルゴリズムを発明した場合、変換も行っています。どちらの状況でも、攻撃者はサーバーを危険にさらす必要があります。前者の場合、攻撃者は定数値を取得することができます。後者の場合、攻撃者はあなたのくだらないことがどのように機能するかを理解し、その逆を行う必要があります。
だから私のポイントは、私はデイブのアイデアは完全にうまくいくと思います(サーバー上でいくつかの変換を行います)が、そのようなあいまいさ/複雑さを追加する必要はありません。そのような方法でますます複雑になると、メンテナンスは地獄のようになる可能性があるためです。サーバー上のペッパーを連結するような「変換」で十分です。ここでもやはり、トレードオフの問題だと思います。そして、Daveのアイデアは最初から正しいです(サーバー側でセキュリティを強化したいと考えています)。
「隠された」カスタムアルゴリズムを使用することには価値がありますが、カスタムセキュアハッシュアルゴリズムを作成する簡単で確立された方法はすでに存在します。 Pepper *
Pepperを使用する非常に安く、非常に迅速で、非常に安全なオプションが存在するため、代わりにゼロから「より安全」な暗号アルゴリズムを作成する人は初心者です。したがって、「デーブのプロトコル」は時間とお金の浪費であるだけでなく、誰かが作成した(おそらく)安全なプロトコルであり、安全なプロトコルについてあまり知らないのです。そして、デイブのプロトコルの実際のセキュリティ(またはその欠如)に関係なく、それは一般に賢明な選択とは見なされていません。
*要するに、コショウはすべてのユーザーにとって同じである秘密の塩です。
経験則:自作のセキュリティは行わないでください。
それはしばしばうまくいかないからです。そしてそれを書いた人はそれをテストすることはできません、誰かがそれを書いている間に何か間違った仮定がある場合、彼/彼女はテストするときにそれをまだ持っています。独立したテストは驚くほど費用がかかり、時間もかかります-書くよりもはるかに。
関連するすべての変更も含める必要があります。 「問題はあり得ないので...」を知ることは、有効なアプローチではありません。上記と同じ理由で。
ソフトウェアのセキュリティは難しいトピックです。とても難しいので、それがどれほど難しいのかさえ理解するのは難しいです。