パスワード暗号化にhash_pbkdf2を使用する場合、塩はセキュリティを確保する上で重要なコンポーネントです。多くの開発者は、 hash_pbkdf2がパスワードベースのキー派生関数であることを知っていますが、塩を正しく安全に生成して使用する方法を無視しています。この記事では、PHPで安全な塩を生成するための塩、一般的な誤解の役割、一般的な誤解、および推奨される慣行について詳細に説明します。
塩の役割は、レインボーテーブル攻撃のリスクと同じハッシュを生成する同じパスワードを防ぐことです。塩がなければ、攻撃者は平文パスワードを反転するためにパスワードハッシュテーブルのみを必要とします。塩を追加すると、各暗号化が一意になり、2人のユーザーが同じパスワードを設定したとしても、ハッシュ値は完全に異なります。
phpのhash_pbkdf2関数プロトタイプは次のとおりです。
<span><span><span class="hljs-keyword">string</span></span><span> </span><span><span class="hljs-title function_ invoke__">hash_pbkdf2</span></span><span> (
</span><span><span class="hljs-keyword">string</span></span><span> </span><span><span class="hljs-variable">$algo</span></span><span>,
</span><span><span class="hljs-keyword">string</span></span><span> </span><span><span class="hljs-variable">$password</span></span><span>,
</span><span><span class="hljs-keyword">string</span></span><span> </span><span><span class="hljs-variable">$salt</span></span><span>,
</span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$iterations</span></span><span>,
</span><span><span class="hljs-keyword">int</span></span><span> </span><span><span class="hljs-variable">$length</span></span><span> = </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-keyword">bool</span></span><span> </span><span><span class="hljs-variable">$binary</span></span><span> = </span><span><span class="hljs-literal">false</span></span><span>
)
</span></span>
$ SALTパラメーターは、ハッシュの一意性を高めるために使用されるため、生成される方法が重要です。
固定文字列を塩として使用します:
<span><span><span class="hljs-variable">$salt</span></span><span> = </span><span><span class="hljs-string">'123456'</span></span><span>;
</span></span>
これは非常に危険な行動です。固定塩とは、すべてのユーザーのハッシュ値が繰り返される可能性が高いことを意味します。
単純な関数を使用して生成します。
たとえば、 uniqid()やmt_rand()などの関数は、ランダムではないか、予測できます。
<span><span><span class="hljs-variable">$salt</span></span><span> = </span><span><span class="hljs-title function_ invoke__">uniqid</span></span><span>();
</span></span>
一見ユニークではありますが、それは十分なエントロピーを欠いており、セキュリティ目的では推奨されていません。
塩を生成するために、PHPが提供する暗号化セキュリティレベル関数を使用することをお勧めします。
<span><span><span class="hljs-variable">$salt</span></span><span> = </span><span><span class="hljs-title function_ invoke__">random_bytes</span></span><span>(</span><span><span class="hljs-number">16</span></span><span>); </span><span><span class="hljs-comment">// 16 バイト = 128 少し</span></span><span>
</span></span>
文字列として保存する必要がある場合(たとえば、データベースに保存)、 bin2hex()またはbase64_encode()を使用してエンコードできます。
<span><span><span class="hljs-variable">$salt</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bin2hex</span></span><span>(</span><span><span class="hljs-title function_ invoke__">random_bytes</span></span><span>(</span><span><span class="hljs-number">16</span></span><span>)); </span><span><span class="hljs-comment">// 32 160文字の文字列</span></span><span>
</span></span>
hash_pbkdf2を使用してパスワードを安全に暗号化する方法の完全な例を次に示します。
<span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">hashPassword</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$password</span></span></span><span>) {
</span><span><span class="hljs-variable">$salt</span></span><span> = </span><span><span class="hljs-title function_ invoke__">bin2hex</span></span><span>(</span><span><span class="hljs-title function_ invoke__">random_bytes</span></span><span>(</span><span><span class="hljs-number">16</span></span><span>)); </span><span><span class="hljs-comment">// 安全に生成します salt</span></span><span>
</span><span><span class="hljs-variable">$iterations</span></span><span> = </span><span><span class="hljs-number">100000</span></span><span>;
</span><span><span class="hljs-variable">$algo</span></span><span> = </span><span><span class="hljs-string">'sha256'</span></span><span>;
</span><span><span class="hljs-variable">$length</span></span><span> = </span><span><span class="hljs-number">64</span></span><span>;
</span><span><span class="hljs-variable">$hash</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_pbkdf2</span></span><span>(</span><span><span class="hljs-variable">$algo</span></span><span>, </span><span><span class="hljs-variable">$password</span></span><span>, </span><span><span class="hljs-variable">$salt</span></span><span>, </span><span><span class="hljs-variable">$iterations</span></span><span>, </span><span><span class="hljs-variable">$length</span></span><span>, </span><span><span class="hljs-literal">false</span></span><span>);
</span><span><span class="hljs-keyword">return</span></span><span> [
</span><span><span class="hljs-string">'salt'</span></span><span> => </span><span><span class="hljs-variable">$salt</span></span><span>,
</span><span><span class="hljs-string">'hash'</span></span><span> => </span><span><span class="hljs-variable">$hash</span></span><span>,
</span><span><span class="hljs-string">'algo'</span></span><span> => </span><span><span class="hljs-variable">$algo</span></span><span>,
</span><span><span class="hljs-string">'iterations'</span></span><span> => </span><span><span class="hljs-variable">$iterations</span></span><span>
];
}
</span><span><span class="hljs-comment">// 使用の例</span></span><span>
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hashPassword</span></span><span>(</span><span><span class="hljs-string">'MySecretPassword'</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$result</span></span><span>);
</span></span>
パスワードを確認するときは、データベースから元の塩、反復、アルゴを読み取り、比較のためにハッシュを再生する必要があります。
<span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">verifyPassword</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$password</span></span></span><span>, </span><span><span class="hljs-variable">$storedHash</span></span><span>, </span><span><span class="hljs-variable">$salt</span></span><span>, </span><span><span class="hljs-variable">$iterations</span></span><span>, </span><span><span class="hljs-variable">$algo</span></span><span> = </span><span><span class="hljs-string">'sha256'</span></span><span>, </span><span><span class="hljs-variable">$length</span></span><span> = </span><span><span class="hljs-number">64</span></span><span>) {
</span><span><span class="hljs-variable">$hash</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_pbkdf2</span></span><span>(</span><span><span class="hljs-variable">$algo</span></span><span>, </span><span><span class="hljs-variable">$password</span></span><span>, </span><span><span class="hljs-variable">$salt</span></span><span>, </span><span><span class="hljs-variable">$iterations</span></span><span>, </span><span><span class="hljs-variable">$length</span></span><span>, </span><span><span class="hljs-literal">false</span></span><span>);
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-title function_ invoke__">hash_equals</span></span><span>(</span><span><span class="hljs-variable">$storedHash</span></span><span>, </span><span><span class="hljs-variable">$hash</span></span><span>);
}
</span></span>
Hash_equalsはタイミング攻撃を防ぐことができ、ハッシュを比較する際に安全な選択です。
hash_pbkdf2を安全に使用するためには、強力なランダム塩を生成し、十分な数の反復を設定することです。静的または低エントロピー塩を使用しないでください。そうしないと、暗号化プロセス全体のセキュリティが破壊されます。パスワードセキュリティの分野では、いわゆる「使用」はありません。すべての詳細は真剣に考える価値があります。この記事が、より安全なPHPアプリケーションを構築するために、 hash_pbkdf2の塩の正しい生成を理解するのに役立つことを願っています。