當前位置: 首頁> 最新文章列表> [PHP中hash_pbkdf2怎么生成安全的salt?你必須知道的正確方式

[PHP中hash_pbkdf2怎么生成安全的salt?你必須知道的正確方式

gitbox 2025-06-15

在使用hash_pbkdf2進行密碼加密時, salt是保障安全性的關鍵組成部分。很多開發者雖然知道hash_pbkdf2是一個基於密碼的密鑰派生函數,但卻忽視瞭如何正確、安全地生成和使用salt 。本文將深入講解salt的作用、常見誤區,以及在PHP 中生成安全salt的推薦做法。

一、為什麼salt至關重要?

salt的作用是防止彩虹表攻擊和相同密碼生成相同哈希的風險。沒有salt ,攻擊者只需要一張事先生成好的密碼-哈希表,就可以反推出明文密碼。而salt的加入使得每次加密結果都獨一無二,即使兩個用戶設置了相同的密碼,其哈希值也完全不同。

二、 hash_pbkdf2簡介

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參數用於增加哈希的唯一性,因此其生成方式至關重要。

三、常見錯誤做法

  1. 使用固定字符串作為salt:

     <span><span><span class="hljs-variable">$salt</span></span><span> = </span><span><span class="hljs-string">'123456'</span></span><span>;
    </span></span>

    這是非常危險的行為。固定salt意味著所有用戶的哈希值很可能重複。

  2. 使用簡單函數生成:

    比如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>

    雖然看似唯一,但缺乏足夠的熵,不推薦用於安全目的。

四、安全生成salt的正確方式

推薦使用PHP 提供的加密安全級別的函數來生成salt

 <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 個字符的十六進製字符串</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> =&gt; </span><span><span class="hljs-variable">$salt</span></span><span>,
        </span><span><span class="hljs-string">'hash'</span></span><span> =&gt; </span><span><span class="hljs-variable">$hash</span></span><span>,
        </span><span><span class="hljs-string">'algo'</span></span><span> =&gt; </span><span><span class="hljs-variable">$algo</span></span><span>,
        </span><span><span class="hljs-string">'iterations'</span></span><span> =&gt; </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>

六、如何驗證密碼?

驗證密碼時,需要從數據庫中讀取出原來的saltiterationsalgo ,再用相同方式重新生成哈希進行比較:

 <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 ,關鍵在於生成強隨機的salt和設置足夠的迭代次數。切忌使用靜態或低熵的salt ,否則將破壞整個加密流程的安全性。在密碼安全領域,沒有所謂的“湊合能用”,每一個細節都值得認真對待。希望本文能幫助你理解hash_pbkdf2salt的正確生成方式,從而構建更加安全的PHP 應用。