PHP開発では、特にパスワード、ハッシュ値、署名などの安全な機密データを処理する場合、文字列を比較することがよくあります。通常、開発者は単純な文字列比較に「==」を使用する傾向があります。ただし、ハッシュ文字列について説明すると、PHPは比較のために特別な関数hash_equals()を提供します。 PHPは、 hash_equals()の代わりに「==」を使用することをお勧めしないのに、後者を推奨するのはなぜですか?この背後にある理由について説明しましょう。
PHPでは、 ==はゆるい比較演算子です。つまり、オペランドのタイプに応じてオペランドを自動的に変換して比較します。この動作は、数字や文字列を扱うときに予想外の結果につながる可能性があります。例えば:
<span><span><span class="hljs-variable">$hash1</span></span><span> = </span><span><span class="hljs-string">"abc"</span></span><span>;
</span><span><span class="hljs-variable">$hash2</span></span><span> = </span><span><span class="hljs-string">"a"</span></span><span> . </span><span><span class="hljs-string">"bc"</span></span><span>;
</span><span><span class="hljs-title function_ invoke__">var_dump</span></span><span>(</span><span><span class="hljs-variable">$hash1</span></span><span> == </span><span><span class="hljs-variable">$hash2</span></span><span>); </span><span><span class="hljs-comment">// 出力: bool(true)</span></span><span>
</span></span>上記の例では、 $ hash1と$ hash2は最初は同じように見えませんが、PHPはゆるい比較を行うときにタイプ変換を行うため、2つの文字列が等しいと仮定します。
さらに重要なことに、PHPは、2つの文字列の文字が異なることがわかっているまで、文字列内の各文字を比較しようとします。ただし、ハッシュ値はバイナリデータの表現であり、セキュリティの観点から各キャラクターの非常に高いストリンジェンシー要件があるため、このようなゆるい比較はハッシュ値には適用されません。わずかな違いがあっても、ハッシュ値は異なると見なす必要があります。したがって、 ==はハッシュ比較には適していません。
==とは異なり、 hash_equals()は、ハッシュ値の比較用に特別に設計されています。それは非常に厳密に動作し、タイプ変換を実行せず、PHPの比較のゆるい影響を受けません。 Hash_equals() 2つの文字列バイトバイトの内容をチェックして、それらがまったく同じであることを確認します。違いがある場合、それはすぐにfalseを返し、文字列またはその他の要因の種類のためにエラーはありません。
さらに、 Hash_equals()には、タイミング攻撃を防ぐという問題もあります。タイミング攻撃は、操作時間の違いを使用して機密データを推測する攻撃方法です。 ==を使用してハッシュ値を直接比較すると、PHPは比較プロセス中にいくつかの情報を漏らし、攻撃者は慎重な観察を通じて異なるハッシュ値の違いを推測する場合があります。 Hash_equals()は、すべての文字が比較された後に結果を与え、したがって、このセキュリティの脆弱性を回避します。
==はゆるい比較であるため、ハッシュ値を処理すると予測不可能な動作が発生する可能性があります。たとえば、ハッシュ比較を行うときに「==」を使用し、入力ハッシュ文字列の長さが一貫していない場合、PHPはそれを満たし、不要な一致になります。 Hash_equals()にはそのような問題はありません。これは、2つの文字列の各バイトを正確に比較して、それらが正確に一貫していることを確認します。
ハッシュ値を比較するために==を使用するリスクの1つは、文字列の長さに関する情報を漏らす可能性です。 PHPが2つのハッシュ文字列の比較で異なる文字列処理アルゴリズムまたは文字変換を使用する場合、攻撃者は時差を通して情報を推測できる場合があります。
Hash_equals()は一定の時間比較を提供します。つまり、入力文字列の実行時間は同じです。これは、タイミング攻撃を防ぐために非常に重要です。
hash_equals()の実装は==よりわずかに遅くなる可能性がありますが、そのセキュリティの利点はこのパフォーマンスオーバーヘッドをはるかに上回ります。特に、パスワードや機密データを扱う場合、セキュリティは常にパフォーマンスよりも優先されるはずです。したがって、場合によっては==がより速く実行されたとしても、 Hash_equals()をHash比較に使用することをお勧めします。
さらに、PHPは、 Hash_equals()を実装する際にパフォーマンスの最適化を実行して、ほとんどの場合に効率的にパフォーマンスを発揮していることを確認しています。
PHPでは、「==」は一般的な比較演算子ですが、特にセキュリティ要件が高い状況では、ハッシュ比較には適していません。 Hash_equals()は、ハッシュ比較用に特別に設計されており、より厳しく安全な検証を提供し、ゆるい比較によって引き起こされる問題を回避できます。特にパスワード、APIキー、デジタル署名などの機密データに関しては、コードのセキュリティを確保するには、ハッシュ比較の場合は常に==の代わりにhash_equals()を使用する必要があります。