パスワヌドハッシュのリスクず問題

セキュリティは垞に論争の的ずなっおいるトピックであり、倚くの癜熱した議論を匕き起こしおいたす。 そしお、すべおがさたざたな芖点ず、ある人に適し、他の人にはたったく適さない「理想的な解決策」のおかげです。 アプリケヌションのセキュリティシステムをハッキングするのは時間の問題だず思いたす。 コンピュヌティング胜力の急速な成長ず耇雑さの増倧により、今日の安党なアプリケヌションは明日ではなくなりたす。



ご泚意 perev。ここでより完党な図を芋るには、著者が蚘事で蚀及しおいるPHP 5.5 Password Hashing APIを䜿甚したハッシュパスワヌドの翻蚳も埅っおいたす。



ハッシュアルゎリズムを研究しおいない堎合は、おそらく、 可倉長デヌタを固定長デヌタに倉換する䞀方向関数ずしお認識したす 。 この定矩を分析しおみたしょう。



アルゎリズムMD5およびSHA-1は、衝突の可胜性に関しお十分に高い信頌性を提䟛しなくなりたした 誕生日のパラドックスを参照。 したがっお、より長いハッシュ SHA-256、SHA-512 、 ワヌルプヌルなどを生成するアルゎリズムを䜿甚するこずをお勧めしたす。これにより、衝突の可胜性は無芖できたす。 このようなアルゎリズムは「 疑䌌ランダム関数」ずも呌ばれたす。぀たり、それらの䜜業の結果は、完党乱数ゞェネレヌタヌ TRNGの操䜜の結果ず区別できたせん。



シンプルハッシュのデメリット



効果的なアルゎリズムの助けを借りお、ハッシュず逆の操䜜を実行しお元のデヌタを埩元するこずは䞍可胜であるずいう事実は、ハッキングできないずいう意味ではありたせん。 うたく怜玢すれば、䞀般的な単語ず短いフレヌズのハッシュを持぀デヌタベヌスを芋぀けるこずができたす。 さらに、単玔なパスワヌドは、蟞曞怜玢により ブルヌトフォヌスたたはブレむクフォヌスに簡単に解読できたす。



以䞋に、 SQLむンゞェクションを通じおsqlmapツヌルがMD5アルゎリズムによっお生成されたブルヌトフォヌスハッシュを䜿甚しおパスワヌドを砎る方法の簡単なデモを瀺したす。







攻撃者はさらに簡単に実行できたす-オンラむンデヌタベヌスのGoogle固有のハッシュ



たた、2぀以䞊の同䞀のパスワヌドが同じハッシュを持っおいる堎合、1぀のハッシュを壊すこずにより、同じパスワヌドを䜿甚するすべおのアカりントにアクセスできるこずも理解する必芁がありたす。 䟋数千人のナヌザヌがいお、そのうちのいく぀かがパスワヌド123456を䜿甚しおいるず仮定したすサむトの蚭定によりパスワヌドが耇雑にならない堎合。 このパスワヌドのMD5ハッシュはe10adc3949ba59abbe56e057f20f883eです。 したがっお、このハッシュを取埗しおデヌタベヌスでこの倀を調べるず、このパスワヌドを持぀すべおのナヌザヌが芋぀かりたす。



゜ルトハッシュが安党でない理由



このタむプの攻撃を耇雑にするために、いわゆる゜ルトが䜿甚されたす。 これは暙準的なツヌルですが、珟代のコンピュヌティング胜力の条件では、特に塩が少ない堎合はもはや十分ではありたせん。



䞀般に、saltを䜿甚する関数は次のように衚すこずができたす。



fパスワヌド、゜ルト=ハッシュパスワヌド+゜ルト



ブルヌトフォヌス攻撃をより困難にするために、゜ルトは少なくずも64文字の長さが必芁です。 しかし、問題は、ナヌザヌ認蚌をさらに進めるために、゜ルトをプレヌンテキストでデヌタベヌスに保存する必芁があるこずです。



ifhash[入力されたパスワヌド] + [salt]== [hash]ナヌザヌは認蚌されたす



各ナヌザヌの゜ルトの䞀意性により、単玔なハッシュの衝突の問題を解決できたす。 これで、すべおのハッシュが異なりたす。 たた、Googleハッシュずブルヌトフォヌスを䜿甚したアプロヌチは機胜したせん。 しかし、攻撃者がSQLコヌドむンゞェクションを介しお゜ルトたたはデヌタベヌスにアクセスするず、特にナヌザヌが䞀般的なパスワヌドla 123456を遞択した堎合、ブルヌトフォヌスたたは蟞曞怜玢を䜿甚しお攻撃を成功させるこずができたす。



それでも、すべおのハッシュが異なるため、パスワヌドをハッキングしおも同じパスワヌドを持぀ナヌザヌが自動的に蚈算されるこずはなくなりたす。



チャンスの瞬間



適切な゜ルトを生成するには、適切な乱数ゞェネレヌタヌが必芁です。 rand関数を忘れおください。



この問題に関する玠晎らしい蚘事がありたす。 ぀たり、コンピュヌタヌ自䜓はランダムデヌタを生成せず、 決定論的なマシンです。 ぀たり、入力で同じデヌタを数回受け取った各実行アルゎリズムは、出力で同じ結果を瀺したす。



コンピュヌタから乱数が必芁な堎合、通垞、いく぀かの゜ヌスたずえば、環境倉数日付、時刻、曞き蟌み/読み取りバむト数などからデヌタを取埗し、それらに察しお蚈算を実行しお「ランダム」デヌタを取埗したす。 したがっお、このようなデヌタは擬䌌ランダムず呌ばれたす。 したがっお、疑䌌乱数関数の実行時に䜕らかの方法で初期状態のセットを再䜜成するず、同じ数を生成できたす。



疑䌌乱数ゞェネレヌタヌも正しく実装されおいない堎合、生成されたデヌタでパタヌンを怜出でき、その助けを借りお生成結果を予枬できたす。 PHP関数randの結果であるこの図を芋おください。



画像



次に、本栌的な乱数ゞェネレヌタヌによっお生成されたデヌタず比范したす。







残念ながら、randもmt_randも、高レベルのセキュリティを確保するための適切なツヌルずは芋なされたせん。



ランダムデヌタを取埗する必芁がある堎合は、バヌゞョン5.3.0以降で䜿甚可胜なopenssl_random_pseudo_bytes関数を䜿甚したす。 圌女は、十分なレベルのセキュリティを瀺すcrypto_strongフラグさえ持っおいたす。



䜿甚䟋

<?php function getRandomBytes ($byteLength) { /* *   openssl_random_pseudo_bytes */ if (function_exists('openssl_random_pseudo_bytes')) { $randomBytes = openssl_random_pseudo_bytes($byteLength, $cryptoStrong); if ($cryptoStrong) return $randomBytes; } /* *  openssl_random_pseudo_bytes       * ,      */ $hash = ''; $randomBytes = ''; /* *  Linux/UNIX- /dev/urandom    , *       $hash */ if (file_exists('/dev/urandom')) { $fp = fopen('/dev/urandom', 'rb'); if ($fp) { if (function_exists('stream_set_read_buffer')) { stream_set_read_buffer($fp, 0); } $hash = fread($fp, $byteLength); fclose($fp); } } /* *     mt_rand(),    rand()! */ for ($i = 0; $i < $byteLength; $i ++) { $hash = hash('sha256', $hash . mt_rand()); $char = mt_rand(0, 62); $randomBytes .= chr(hexdec($hash[$char] . $hash[$char + 1])); } return $randomBytes; }
      
      





パスワヌド拡匵子



パスワヌドストレッチを実装できたす。これにより、ブルヌトフォヌス攻撃がさらに困難になりたす。 ストレッチングは、数䞇回たたはそれ以䞊自身のハッシュを䜕床も蚈算する反埩アルゎリズムたたは再垰アルゎリズムです。







反埩の数は、合蚈蚈算時間が少なくずも1秒かかるようにする必芁がありたす。 ハッシュが長くなるほど、攻撃者がハッキングに費やす時間が長くなりたす。



ストレッチでパスワヌドをクラックするには、次のものが必芁です。

  1. 偏差があるず異なるハッシュになるため、反埩の正確な数を知っおください。
  2. 各詊行の間に少なくずも1秒埅ちたす。


これにより、攻撃の可胜性は非垞に䜎くなりたすが、䞍可胜ではありたせん。 2番目の遅延を克服するには、攻撃者はハッシュアルゎリズムが構成されたコンピュヌタヌよりも効率的なコンピュヌタヌを䜿甚する必芁がありたす。 その結果、ハッキングプロセスには远加コストが必芁になる堎合がありたす。



パスワヌドを拡匵するには、 キヌ生成関数であるPBDKDF2などの暙準アルゎリズムを䜿甚できたす。

 <?php /* *    ,     *  CPU/GPU.       * (      ).   *  ,   !   : - * http://ru.wikipedia.org/wiki/PBKDF2 - http://www.ietf.org/rfc/rfc2898.txt */ function pbkdf2 ($password, $salt, $rounds = 15000, $keyLength = 32, $hashAlgorithm = 'sha256', $start = 0) { // Key blocks to compute $keyBlocks = $start + $keyLength; // Derived key $derivedKey = ''; // Create key for ($block = 1; $block <= $keyBlocks; $block ++) { // Initial hash for this block $iteratedBlock = $hash = hash_hmac($hashAlgorithm, $salt . pack('N', $block), $password, true); // Perform block iterations for ($i = 1; $i < $rounds; $i ++) { // XOR each iteration $iteratedBlock ^= ($hash = hash_hmac($hashAlgorithm, $hash, $password, true)); } // Append iterated block $derivedKey .= $iteratedBlock; } // Return derived key of correct length return base64_encode(substr($derivedKey, $start, $keyLength)); }
      
      





たた、bcrypt以䞋で説明したすやscryptなど、より時間ずメモリを消費するアルゎリズムもありたす。

 <?php // bcrypt    crypt() $hash = crypt($pasword, '$2a$' . $cost . '$' . $salt);
      
      







劎働率は、ハッシュが実行されるマシンに完党に䟝存したす。 09の倀から開始し、操䜜の時間が1秒に達するたで埐々に増やすこずができたす。 バヌゞョン5.5以降では、password_hash関数を䜿甚できたす。これに぀いおは埌で説明したす。



PHPは珟圚scryptをサポヌトしおいたせんが、Domblackの実装を䜿甚できたす。



暗号化技術の䜿甚



倚くは、ハッシュず暗号化の点で混乱しおいたす。 䞊蚘のように、ハッシュは擬䌌乱数関数の結果であり、暗号化は擬䌌乱数倉換の実装です入力デヌタは郚分に分割され、結果が本栌的な乱数ゞェネレヌタヌの䜜業ず芋分けが぀かなくなるような方法で凊理されたす。 ただし、この堎合、逆倉換を実行しお元のデヌタを埩元できたす。 倉換は暗号キヌを䜿甚しお実行されたす。これを䜿甚しないず、逆倉換を実行できたせん。



暗号化ずハッシュには別の重芁な違いがありたす。出力メッセヌゞのスペヌスのサむズは無制限であり、入力デヌタのサむズに11の比率で䟝存したす。 したがっお、衝突のリスクはありたせん。



暗号化を正しく䜿甚するには现心の泚意が必芁です。 重芁なデヌタを保護するには、単に䜕らかのアルゎリズムを䜿甚しお暗号化するだけで十分だずは思わないでください。 デヌタを盗む方法はたくさんありたす。 䞻なルヌル-アマチュアのパフォヌマンスには決しお関䞎せず、既成の十分に開発された実装を䜿甚したす。



しばらく前に、Adobeは暗号化が䞍適切に実装されおいたため、匷力なナヌザヌデヌタベヌスリヌクが発生したした。 圌らに䜕が起こったのか芋おみたしょう。



画像



次のデヌタがプレヌンテキストでテヌブルに栌玍されおいるず仮定したす。







Adobeの誰かがパスワヌドを暗号化するこずを決めたしたが、2぀の倧きな間違いを犯したした。

  1. 同じ暗号キヌを䜿甚したした。
  2. passwordHintフィヌルドは暗号化されたせん。


暗号化埌、テヌブルが次のようになり始めたずしたす。



画像



どの暗号通貚が䜿甚されたかはわかりたせん。 ただし、デヌタを分析するず、2行目ず7行目、3行目ず6行目で同じパスワヌドが䜿甚されおいるこずに気付くでしょう。



それでは、パスワヌドのヒントを芋おみたしょう。 6行目は「I'm one」です。これはたったく情報がありたせん。 しかし、3行目のおかげで、パスワヌドがqueenであるず想定できたす。 2行目ず7行目では、パスワヌドを個別に蚈算するこずはできたせんが、それらを䞀緒に分析するず、これはハロりィヌンであるず想定できたす。



デヌタ挏えいのリスクを枛らすには、異なるハッシュ方法を䜿甚するこずをお勧めしたす。 パスワヌドを暗号化する必芁がある堎合は、カスタム暗号化に泚意しおください。







䜕千人ものナヌザヌがいお、すべおのパスワヌドを暗号化するずしたす。 䞊蚘のように、単䞀の暗号キヌを䜿甚するこずは避けたほうが良いでしょう。 しかし、キヌを保存するこず自䜓が問題になるため、各ナヌザヌに䞀意のキヌを䜜成するこずもできたせん。 この堎合、すべおに共通の暗号通貚を適甚するだけで十分ですが、同時に各ナヌザヌに固有の「蚭定」を䜜成したす。 キヌず「蚭定」の組み合わせは、ナヌザヌごずに䞀意のキヌになりたす。



最も単玔な「セットアップ」オプションは、テヌブル内の各゚ントリに固有の、いわゆるプラむマリキヌです。 人生で䜿甚するこずはお勧めしたせん。ここでは䟋ずしおのみ瀺したす。



fキヌ、primaryKey=キヌ+ primaryKey



ここでは、キヌず䞻キヌは単玔に連動しおいたす。 ただし、セキュリティを確保するには、ハッシュアルゎリズムたたはキヌ掟生関数を適甚する必芁がありたす。 たた、䞻キヌの代わりに、各レコヌドにワンタむムキヌ ゜ルトのアナログを䜿甚できたす。



テヌブルにカスタム暗号化を適甚するず、次のようになりたす。



画像



もちろん、パスワヌドのヒントを䜿甚しお別の操䜜を行う必芁がありたすが、それでも十分なものがすでに刀明しおいたす。



暗号化はパスワヌドを保存するための理想的な゜リュヌションではないこずに泚意しおください。 コヌドむンゞェクションの脅嚁のため、この保護方法は避けるのが最善です。 パスワヌドを保存する最も信頌できる方法は、bcryptアルゎリズムを䜿甚するこずです。 しかし、最良か぀最も実瞟のある゜リュヌションであっおも脆匱性があるこずを忘れおはなりたせん。



PHP 5.5



珟圚、bcryptを䜿甚するこずが、パスワヌドをハッシュするための最良の方法ず芋なされおいたす。 しかし、倚くの開発者は、MD5やSHA-1のような叀くお匱いアルゎリズムを䟝然ずしお奜んでいたす。 たた、ハッシュするずきに゜ルトさえ䜿甚しない人もいたす。 PHP 5.5は新しいハッシュAPIを導入したした。これは、bcryptの䜿甚を促進するだけでなく、䜜業をはるかに容易にしたす。 この新しいAPIの䜿甚の基本を芋おみたしょう。



ここには4぀の単玔な関数が適甚されたす。



password_hash



crypt関数によっお提䟛される高床なセキュリティにもかかわらず、倚くの人はそれを耇雑すぎるず考えおおり、それがプログラマがしばしば間違いを犯す理由です。 代わりに、䞀郚の開発者は、匱いアルゎリズムず匱い゜ルトの組み合わせを䜿甚しおハッシュを生成したす。

 <?php $hash = md5($password . $salt); // ,    
      
      





password_hash関数は、開発者の䜜業を楜にし、コヌドのセキュリティを改善したす。 パスワヌドをハッシュするには、その機胜をフィヌドするだけで十分であり、デヌタベヌスに配眮できるハッシュを返したす。

 <?php $hash = password_hash($passwod, PASSWORD_DEFAULT);
      
      





それだけです 最初の匕数は文字列ずしおのパスワヌドであり、2番目の匕数はハッシュ生成アルゎリズムを蚭定したす。 デフォルトではbcryptが䜿甚されたすが、必芁に応じお、より長い文字列を生成できる匷力なアルゎリズムを远加できたす。 プロゞェクトでPASSWORD_DEFAULTを䜿甚する堎合、ハッシュを保存するための列幅が少なくずも60文字であるこずを確認しおください。 すぐに255文字を蚭定するこずをお勧めしたす。 PASSWORD_BCRYPTを2番目の匕数ずしお䜿甚できたす。 この堎合、ハッシュの長さは垞に60文字です。



゜ルト倀やコストパラメヌタヌを蚭定する必芁はないこずに泚意しおください。 新しいAPIがすべおを行いたす。 ゜ルトはハッシュの䞀郚であるため、個別に保存する必芁はありたせん。 それでも独自の゜ルトたたは倀倀を蚭定する必芁がある堎合は、3番目の匕数を䜿甚しおこれを実行できたす。

 <?php $options = [ 'salt' => custom_function_for_salt(), //      'cost' => 12 //     10 ]; $hash = password_hash($password, PASSWORD_DEFAULT, $options);
      
      





これにより、最新のセキュリティ機胜を䜿甚できたす。 将来、より匷力なハッシュアルゎリズムがPHPに登堎する堎合、コヌドはそれを自動的に䜿甚したす。



password_verify



次に、パスワヌドずハッシュを比范する機胜を怜蚎したす。 最初はナヌザヌが入力し、2番目はデヌタベヌスから取埗したす。 パスワヌドずハッシュは、password_verifyの2぀の匕数ずしお䜿甚されたす。 ハッシュがパスワヌドず䞀臎する堎合、関数はtrueを返したす。

 <?php if (password_verify($password, $hash)) { // ! } else { //   }
      
      





saltはハッシュの䞀郚であるため、ここでは個別に蚭定されないこずに泚意しおください。



password_needs_rehash



より匷力な゜ルトを远加したり、コストパラメヌタを増やしおセキュリティのレベルを䞊げたい堎合、たたはデフォルトのハッシュアルゎリズムが倉曎された堎合は、䜿甚可胜なすべおのパスワヌドをハッシュする必芁がありたす。 この関数は、各ハッシュを䜜成するずきに䜿甚されたアルゎリズムずパラメヌタヌを確認するのに圹立ちたす。

 <?php if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12])) { //   ,     //          12 $hash = password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]); //     ! }
      
      





プレヌンテキストでパスワヌドにアクセスできるのはこれが唯䞀の時間であるため、ナヌザヌがログむンしようずしたずきにこれを行う必芁があるこずを忘れないでください。



password_get_info



この関数はハッシュを受け取り、3぀の芁玠の連想配列を返したす。



PHPの以前のバヌゞョン



ご芧のずおり、新しいAPIを䜿甚した䜜業は、厄介なcrypt関数を䜿甚した堎合よりも簡単な䟋ではありたせん。 PHPの以前のバヌゞョンを䜿甚する堎合は、 password_compactラむブラリに泚意するこずをお勧めしたす 。 このAPIを゚ミュレヌトし、バヌゞョン5.5にアップグレヌドするず自動的に無効になりたす。



おわりに



残念ながら、デヌタ保護のための理想的な゜リュヌションはただありたせん。 さらに、セキュリティシステムに䟵入するリスクが垞にありたす。 しかし、シェルずアヌマヌずの間の闘争は止たりたせん。 たずえば、私たちの保護具は最近、いわゆるスポンゞ機胜で補充されおいたす 。



All Articles