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

如何基于密码在数据库存储加密文本并查询解密?

解决加密文本存储与解密还原的问题

哦,我太懂你现在的困惑了!你踩了一个非常常见的坑:把哈希算法和加密算法搞混了。password_hash和hash_hmac都是不可逆的哈希工具——它们的唯一作用是验证「输入的内容和原内容是否一致」,根本没法还原出原始文本。要实现「加密存库、密码验证后解密还原」的需求,你得用对称加密算法,比如AES-256-GCM(这是当前安全标准级别的选择)。

核心思路

  1. 用用户提供的密码+固定salt生成一个安全的加密密钥(结合pepper增强安全性)
  2. 用这个密钥对原始文本进行对称加密,把加密后的内容、初始化向量(IV)、校验标签一起存入数据库
  3. 查询时,用用户输入的密码重新生成密钥,再结合存库的IV和标签解密出原始文本

完整PHP代码实现

<?php
// 建议把这些敏感配置放到环境变量里,不要硬编码在代码中
$salt = 'c0d4#';
$pepper = 'nsa-cia-fbi';
$cipher = 'aes-256-gcm'; // 安全的加密模式,自带完整性校验

/**
 * 从密码生成加密密钥
 */
function generateEncryptionKey(string $password, string $salt, string $pepper): string
{
    // 把pepper和密码拼接,再用PBKDF2生成密钥(比单纯hash更安全)
    $passwordWithPepper = $password . $pepper;
    // 生成32字节的密钥(对应AES-256)
    return hash_pbkdf2('sha256', $passwordWithPepper, $salt, 100000, 32, true);
}

/**
 * 加密文本
 */
function encryptText(string $plaintext, string $key, string $cipher): array
{
    // 生成随机初始化向量(IV),每个加密都要不同
    $ivLength = openssl_cipher_iv_length($cipher);
    $iv = openssl_random_pseudo_bytes($ivLength);
    
    // 加密,同时生成GCM模式需要的校验标签
    $ciphertext = openssl_encrypt($plaintext, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag);
    
    // 返回需要存储的所有数据:加密文本、IV、标签(都转base64方便存库)
    return [
        'ciphertext' => base64_encode($ciphertext),
        'iv' => base64_encode($iv),
        'tag' => base64_encode($tag)
    ];
}

/**
 * 解密文本
 */
function decryptText(string $ciphertext, string $iv, string $tag, string $key, string $cipher): ?string
{
    // 把base64编码的内容转回原始字节
    $ciphertextRaw = base64_decode($ciphertext);
    $ivRaw = base64_decode($iv);
    $tagRaw = base64_decode($tag);
    
    // 解密并校验标签(确保内容没被篡改)
    $plaintext = openssl_decrypt($ciphertextRaw, $cipher, $key, OPENSSL_RAW_DATA, $ivRaw, $tagRaw);
    
    return $plaintext !== false ? $plaintext : null;
}

// ------------------- 示例:加密并存储到数据库 -------------------
$userPassword = 'your-user-password'; // 用户输入的密码
$secretText = '这是需要加密存储的秘密文本'; // 原始秘密内容

// 生成密钥
$encryptionKey = generateEncryptionKey($userPassword, $salt, $pepper);

// 加密文本
$encryptedData = encryptText($secretText, $encryptionKey, $cipher);

// 这里模拟把encryptedData存入数据库(比如存到一个表的ciphertext、iv、tag字段)
// $pdo->prepare("INSERT INTO secret_data (ciphertext, iv, tag) VALUES (?, ?, ?)")->execute([$encryptedData['ciphertext'], $encryptedData['iv'], $encryptedData['tag']]);

// ------------------- 示例:查询并解密 -------------------
// 假设从数据库取出存储的数据
$storedCiphertext = $encryptedData['ciphertext'];
$storedIv = $encryptedData['iv'];
$storedTag = $encryptedData['tag'];

// 用户查询时输入的密码
$inputPassword = 'your-user-password';

// 重新生成密钥(用输入的密码)
$decryptionKey = generateEncryptionKey($inputPassword, $salt, $pepper);

// 解密
$decryptedText = decryptText($storedCiphertext, $storedIv, $storedTag, $decryptionKey, $cipher);

if ($decryptedText !== null) {
    echo "解密成功!原始文本:" . $decryptedText;
} else {
    echo "密码错误或数据已被篡改!";
}
?>

关键注意事项

  • 不要硬编码salt和pepper:把它们放到服务器的环境变量里,避免代码泄露导致密钥被破解
  • IV必须随机且唯一:每次加密都要生成新的IV,不能重复使用,否则会降低安全性
  • GCM标签必须一起存储:它用来验证加密内容是否被篡改,解密时必须提供
  • 密码复杂度:提醒用户使用强密码,否则即使加密算法再安全,也可能被暴力破解

内容的提问来源于stack exchange,提问作者code-8

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:37:50