You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP 8.1.16+如何兼容旧版crypt()含非法盐的哈希行为?

问题解答

能否在新版PHP中复刻旧版crypt()行为?

很难直接在新版PHP中原封不动复刻该行为——PHP 8.1.16的这个变更属于底层加密库的安全合规性修复,官方没有提供开关回退到旧逻辑。但可以通过两种方式模拟旧版行为:

  • 手动修复盐值后调用新版crypt():
    旧版crypt()对不符合Blowfish规范的盐会自动将非法字符(如$)替换为.,并调整盐长度到标准的22位。你可以手动对原始预存盐做相同处理,生成合规的Blowfish盐后调用新版crypt()。
    以你的示例为例,原始盐$2a$05$SomeBadSaltHasDollar/$中的末尾$替换为.后,得到合规盐$2a$05$SomeBadSaltHasDollar.,用这个盐调用crypt()即可生成与旧版一致的哈希。
  • 搭建旧版PHP验证服务:
    部署一个PHP 8.1.15及以下版本的轻量服务,提供简单接口接收用户凭证和原始盐,返回旧版crypt()生成的哈希。新版PHP通过调用该接口获取验证所需的哈希值,这是最稳妥的模拟方式。

无法复刻时,如何利用现有旧数据?

如果上述模拟方式不可行,可通过以下方案处理:

  1. 用户登录时迁移数据:
    • 用户输入凭证后,先通过旧版逻辑(如调用旧版PHP服务)验证旧哈希是否匹配。
    • 验证成功后,立即用合规的哈希方案(如password_hash())重新生成凭证的哈希,替换数据库中的旧哈希。后续验证直接使用新版PHP的标准哈希逻辑。
  2. 尝试用旧哈希直接验证:
    新版crypt()支持用完整哈希作为盐值,自动提取其中的有效盐部分进行验证,你可以尝试这个逻辑:
    $userInput = 'my password';
    $oldHash = '$2a$05$SomeBadSaltHasDollar/.ry.LY8GXnJWLU9/BIJ5I4VJPRBlp6z.';
    $newHash = crypt($userInput, $oldHash);
    if ($newHash === $oldHash) {
        // 验证成功,可查询对应ImportantValue
    }
    
    注意:如果旧哈希的盐部分仍包含非法字符,新版crypt()仍会返回*0,此时仍需结合旧版服务完成验证。

内容的提问来源于stack exchange,提问作者Michael David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 04:26:09