Current Location: Home> Latest Articles> How to Securely Store Keys Generated by the hash_pbkdf2 Function?

How to Securely Store Keys Generated by the hash_pbkdf2 Function?

gitbox 2025-07-02

1. Understanding the hash_pbkdf2 Function

hash_pbkdf2 is a PHP function used to generate keys using the Password-Based Key Derivation Function 2 (PBKDF2). PBKDF2 enhances security through multiple hashing rounds combined with salting, effectively defending against brute force and dictionary attacks.

<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-string">"sha256"</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>

Parameter Explanation:

  • "sha256": The chosen hashing algorithm, here SHA-256 is used.

  • $password: The user-inputted password.

  • $salt: A randomly generated salt to enhance encryption security.

  • $iterations: The number of hashing iterations; the higher the count, the harder it is to crack.

  • $length: The length of the generated key.

  • false: Whether to output raw binary data; usually set to false to output a hexadecimal string.

The security of PBKDF2 depends heavily on the salt and iteration count. Proper configuration of these parameters significantly improves key storage security.


2. Secure Storage of the Generated Key

2.1 Enhance Security with Salt and Multiple Iterations

When generating keys, it is crucial to use a randomly generated salt ($salt). The salt prevents identical passwords from producing the same key, further increasing the difficulty of brute-force attacks. The salt length is typically recommended to be at least 16 bytes to ensure sufficient randomness.

Setting a sufficiently high number of iterations in hash_pbkdf2 is also essential. In theory, the more iterations, the longer it takes to generate the key and the harder it is to crack. A recommended minimum iteration count is 100,000. This approach forces attackers to spend more time and computing resources on brute-force attempts.

<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">// Generate a 16-byte random 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 class="hljs-comment">// At least 100,000 iterations</span></span><span>
</span><span><span class="hljs-variable">$key</span></span><span> = </span><span><span class="hljs-title function_ invoke__">hash_pbkdf2</span></span><span>(</span><span><span class="hljs-string">"sha256"</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-number">64</span></span><span>, </span><span><span class="hljs-literal">false</span></span><span>); </span><span><span class="hljs-comment">// 64-byte key</span></span><span>
</span></span>

2.2 Avoid Storing Raw Passwords

Storing raw user passwords is a highly insecure practice. In PHP, you should always store the hashed key instead of the original password string. The key generated by hash_pbkdf2 is already processed through multiple encryption rounds and cannot theoretically be reversed to the original password.

For example, the generated key can be stored in a database alongside other user information:

<span><span><span class="hljs-comment">// Store key hash and salt in the database</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable">$pdo</span></span><span>-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"INSERT INTO users (username, password_hash, salt) VALUES (?, ?, ?)"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>([</span><span><span class="hljs-variable">$username</span></span><span>, </span><span><span class="hljs-variable">$key</span></span><span>, </span><span><span class="hljs-variable">$salt</span></span><span>]);
</span></span>

2.3 Use Dedicated Encryption Storage

To further improve key security, consider encrypting stored keys with a stronger encryption algorithm. For example, you can use a symmetric encryption algorithm like AES to encrypt the generated key before storage. In this case, the security of key storage depends not only on the PBKDF2 hash but also on an additional encryption layer.

<span><span><span class="hljs-variable">$encryption_key</span></span><span> = </span><span><span class="hljs-string">&#039;your-secure-encryption-key&#039;</span></span><span>;
</span><span><span class="hljs-variable">$encrypted_key</span></span><span> = </span><span><span class="hljs-title function_ invoke__">openssl_encrypt</span></span><span>(</span><span><span class="hljs-variable">$key</span></span><span>, </span><span><span class="hljs-string">&#039;AES-256-CBC&#039;</span></span><span>, </span><span><span class="hljs-variable">$encryption_key</span></span><span>, </span><span><span class="hljs-number">0</span></span><span>, </span><span><span class="hljs-variable">$iv</span></span><span>);
</span></span>

Note that when encrypting keys, the encryption key ($encryption_key) itself must be securely stored. It should reside in a highly secure environment, such as a hardware security module (HSM) or a key management service.


3. Preventing Password Leakage

3.1 Database Security

Beyond protecting the keys themselves, the security of the entire database is crucial. Make sure database access permissions are tightly controlled, and use strong passwords and encrypted connections (e.g., SSL/TLS) to prevent man-in-the-middle attacks and data leaks.

The database should follow the principle of least privilege, allowing access to sensitive data only to authorized users.

3.2 Regularly Update Keys and Salts

For long-term security, regularly updating keys and salts is an effective measure. While updating keys is not straightforward, periodically rehashing passwords and replacing salts can reduce the risk of exposure.

For instance, users can be prompted to change their passwords after logging in, with new salts and keys used to re-encrypt stored credentials.

3.3 Prevent SQL Injection and Brute Force Attacks

Preventing SQL injection attacks is a fundamental step in ensuring secure key storage. Always sanitize user input in database queries or use prepared statements to avoid SQL injection vulnerabilities.

To mitigate brute force attacks, implement limits on login attempts, introduce CAPTCHA mechanisms, and monitor suspicious login activities.