当前位置: 首页> 最新文章列表> 使用hash_pbkdf2函数生成密钥后,如何确保其安全存储?

使用hash_pbkdf2函数生成密钥后,如何确保其安全存储?

gitbox 2025-07-02

1. 理解 hash_pbkdf2 函数

hash_pbkdf2 是 PHP 提供的一个函数,用于使用密码基于密钥的哈希函数(PBKDF2)生成密钥。PBKDF2 是一种通过多次哈希和加盐技术增强安全性的算法,可以有效防止暴力破解和字典攻击。

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

参数解析:

  • "sha256": 选择的哈希算法,这里使用 SHA-256。

  • $password: 用户输入的密码。

  • $salt: 随机生成的盐值,用来增加加密的安全性。

  • $iterations: 哈希迭代次数,迭代次数越高,破解难度越大。

  • $length: 生成密钥的长度。

  • false: 是否输出二进制结果,通常设置为false,输出十六进制字符串。

PBKDF2的安全性依赖于盐值和迭代次数,合理设置这些参数能够极大提升密钥存储的安全性。


2. 安全存储生成的密钥

2.1 使用加盐与多次迭代增强安全性

生成密钥时,首先要确保使用随机生成的盐值($salt)。盐值的作用是避免相同的密码生成相同的密钥,进一步增加暴力破解的难度。盐值的长度通常建议至少为16字节,以确保其随机性。

hash_pbkdf2中设置足够的迭代次数也是至关重要的。理论上,迭代次数越多,生成密钥的时间就越长,破解的难度也越大。一般推荐的迭代次数至少为100,000次。通过这种方式,攻击者需要更多的时间和计算资源来暴力破解密钥。

<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">// 生成16字节的随机盐值</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-comment">// 至少100,000次迭代</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字节的密钥</span></span><span>
</span></span>

2.2 不存储原始密码

直接存储用户的原始密码是非常不安全的做法。在PHP中,应该始终存储密钥的哈希值,而不是原始的密码字符串。通过hash_pbkdf2生成的密钥已经经过多次加密和处理,理论上无法从中恢复出原始的密码。

例如,生成的密钥值可以存储在数据库中,并与用户的其他信息一起保存:

<span><span><span class="hljs-comment">// 将密钥哈希值和盐值存入数据库</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable">$pdo</span></span><span>-&gt;</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>-&gt;</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 使用独立的加密存储

为了进一步增强密钥的安全性,可以考虑使用更强的加密算法来加密存储的密钥。例如,可以使用对称加密算法(如AES)对生成的密钥进行加密存储。在这种情况下,密钥存储不仅依赖于PBKDF2生成的哈希,还依赖于额外的加密层。

<span><span><span class="hljs-variable">$encryption_key</span></span><span> = </span><span><span class="hljs-string">'your-secure-encryption-key'</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">'AES-256-CBC'</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>

注意,在加密密钥时,必须确保加密密钥($encryption_key)的安全存储。加密密钥本身应该存储在一个高度安全的地方,如硬件安全模块(HSM)或密钥管理服务中。


3. 防止密码泄露

3.1 数据库的安全

除了对密钥本身进行保护外,整个数据库的安全也至关重要。确保数据库的访问权限受到严格控制,使用强密码和加密连接(如SSL/TLS)来防止中间人攻击和数据泄露。

数据库应该采取最小权限原则,只允许授权用户访问敏感数据。

3.2 定期更新密钥和盐值

为了提高长期安全性,定期更新密钥和盐值也是一种有效的安全措施。虽然更新密钥并不简单,但如果能周期性地重新哈希并更换盐值,就可以防止泄露的风险。

例如,可以在用户登录后,定期提示用户更改密码,并使用新的盐值和密钥重新加密存储。

3.3 防止SQL注入和暴力破解攻击

防止SQL注入攻击是确保密钥安全存储的基本步骤。确保数据库查询中的用户输入经过充分的转义,或者使用预处理语句来避免SQL注入漏洞。

对于暴力破解攻击,可以通过限制登录尝试次数、引入验证码机制以及监控可疑的登录行为等手段来减少风险。