PHP 怎么加密存储

wen PHP项目 1

本文目录导读:

PHP 怎么加密存储

  1. 密码加密(最常用)
  2. 对称加密(AES-256)
  3. 非对称加密(RSA)
  4. 哈希(单向加密)
  5. 数据库层面的加密
  6. 完整的安全实践建议
  7. 安全最佳实践总结

在 PHP 中加密存储敏感数据(如密码、API密钥、个人信息等)是一个重要的安全实践,以下是几种常见且安全的加密存储方案:

密码加密(最常用)

使用 password_hash()password_verify()(推荐)

// 加密(存储时)
$password = 'user_password_123';
$hashedPassword = password_hash($password, PASSWORD_DEFAULT); 
// 输出类似:$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi
// 存入数据库
$stmt = $pdo->prepare("INSERT INTO users (username, password) VALUES (?, ?)");
$stmt->execute([$username, $hashedPassword]);
// 验证(登录时)
$inputPassword = 'user_input_password';
$storedHash = $row['password'];
if (password_verify($inputPassword, $storedHash)) {
    echo "密码正确";
} else {
    echo "密码错误";
}
// 检查是否需要重新哈希
if (password_needs_rehash($storedHash, PASSWORD_DEFAULT)) {
    $newHash = password_hash($inputPassword, PASSWORD_DEFAULT);
    // 更新数据库
}

对称加密(AES-256)

适用于需要解密的数据(如身份证号、银行卡等)。

// 定义加密类
class Crypto {
    private $key;
    private $cipher = 'aes-256-gcm';
    public function __construct(string $encryptionKey) {
        $this->key = hash('sha256', $encryptionKey, true);
    }
    // 加密
    public function encrypt(string $plaintext): string {
        $ivlen = openssl_cipher_iv_length($this->cipher);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $tag = '';
        $ciphertext = openssl_encrypt(
            $plaintext, 
            $this->cipher, 
            $this->key, 
            OPENSSL_RAW_DATA, 
            $iv, 
            $tag
        );
        if ($ciphertext === false) {
            throw new Exception('加密失败: ' . openssl_error_string());
        }
        // 将 IV 和 tag 一起存储
        return base64_encode($iv . $tag . $ciphertext);
    }
    // 解密
    public function decrypt(string $encryptedData): string {
        $data = base64_decode($encryptedData);
        $ivlen = openssl_cipher_iv_length($this->cipher);
        $iv = substr($data, 0, $ivlen);
        $tag = substr($data, $ivlen, 16); // GCM tag 是 16 字节
        $ciphertext = substr($data, $ivlen + 16);
        $plaintext = openssl_decrypt(
            $ciphertext, 
            $this->cipher, 
            $this->key, 
            OPENSSL_RAW_DATA, 
            $iv, 
            $tag
        );
        if ($plaintext === false) {
            throw new Exception('解密失败');
        }
        return $plaintext;
    }
}
// 使用示例
$crypto = new Crypto('secret_key_here');
$encrypted = $crypto->encrypt('1234567890');
echo "加密后: " . $encrypted . "\n";
echo "解密后: " . $crypto->decrypt($encrypted);

非对称加密(RSA)

适用于双向通信或多方共享数据。

// 生成密钥对
$config = [
    'private_key_bits' => 2048,
    'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
$keyPair = openssl_pkey_new($config);
// 提取公钥和私钥
openssl_pkey_export($keyPair, $privateKey);
$publicKey = openssl_pkey_get_details($keyPair)['key'];
// 加密(使用公钥)
function rsaEncrypt(string $data, string $publicKey): string {
    $encrypted = '';
    // 分段加密(因为 RSA 有长度限制)
    $chunkSize = 245; // 2048位RSA最大加密长度
    $dataChunks = str_split($data, $chunkSize);
    foreach ($dataChunks as $chunk) {
        $encryptedChunk = '';
        openssl_public_encrypt($chunk, $encryptedChunk, $publicKey);
        $encrypted .= $encryptedChunk;
    }
    return base64_encode($encrypted);
}
// 解密(使用私钥)
function rsaDecrypt(string $encryptedData, string $privateKey): string {
    $data = base64_decode($encryptedData);
    $decrypted = '';
    $chunkSize = 256; // 2048位RSA最大解密长度
    $dataChunks = str_split($data, $chunkSize);
    foreach ($dataChunks as $chunk) {
        $decryptedChunk = '';
        openssl_private_decrypt($chunk, $decryptedChunk, $privateKey);
        $decrypted .= $decryptedChunk;
    }
    return $decrypted;
}
// 使用示例
$data = "敏感数据";
$encrypted = rsaEncrypt($data, $publicKey);
$decrypted = rsaDecrypt($encrypted, $privateKey);
echo "解密结果: " . $decrypted;

哈希(单向加密)

适用于无需解密的场景(如验证数据完整性)。

// SHA-256 哈希
$hash = hash('sha256', $data);
// HMAC(带密钥的哈希)
$key = 'secret_key';
$hmac = hash_hmac('sha256', $data, $key);
// 加盐哈希
$salt = bin2hex(random_bytes(16));
$saltedHash = hash('sha256', $salt . $data);
// Bcrypt
$bcryptHash = password_hash($data, PASSWORD_BCRYPT, ['cost' => 12]);
// Argon2id(最安全)
$argon2Hash = password_hash($data, PASSWORD_ARGON2ID, [
    'memory_cost' => 65536, // 64MB
    'time_cost' => 4,
    'threads' => 1
]);

数据库层面的加密

// MySQL AES 加密/解密
$query = "INSERT INTO users (name, ssn) VALUES (?, AES_ENCRYPT(?, ?))";
$stmt = $pdo->prepare($query);
$stmt->execute([$name, $ssn, $encryptionKey]);
$query = "SELECT AES_DECRYPT(ssn, ?) as ssn_decrypted FROM users WHERE id = ?";
$stmt = $pdo->prepare($query);
$stmt->execute([$encryptionKey, $userId]);
$row = $stmt->fetch();
echo $row['ssn_decrypted'];

完整的安全实践建议

class SecureData {
    private $pdo;
    private $encryptionKey;
    public function __construct(\PDO $pdo, string $key) {
        $this->pdo = $pdo;
        $this->encryptionKey = $key;
    }
    // 安全存储密码
    public function storePassword(int $userId, string $password): bool {
        $hashed = password_hash($password, PASSWORD_DEFAULT);
        $stmt = $this->pdo->prepare(
            "UPDATE users SET password_hash = ? WHERE id = ?"
        );
        return $stmt->execute([$hashed, $userId]);
    }
    // 安全存储敏感数据
    public function storeSensitiveData(int $userId, string $type, string $data): bool {
        // 生成唯一的 IV
        $iv = random_bytes(16);
        $ciphertext = openssl_encrypt(
            $data,
            'aes-256-cbc',
            $this->encryptionKey,
            0,
            $iv
        );
        $stmt = $this->pdo->prepare(
            "INSERT INTO encrypted_data (user_id, data_type, iv, ciphertext) 
             VALUES (?, ?, ?, ?)"
        );
        return $stmt->execute([
            $userId, 
            $type, 
            base64_encode($iv), 
            $ciphertext
        ]);
    }
    // 环境变量中的密钥(推荐)
    // 不要硬编码密钥在代码中
    public function getKey(): string {
        return getenv('APP_ENCRYPTION_KEY') ?: 
               parse_ini_file('/secure/config.ini')['encryption_key'];
    }
}

安全最佳实践总结

  1. 密码永远使用单向哈希password_hash() + password_verify()
  2. 敏感数据使用 AES-256-GCM:带有认证标签,防篡改
  3. 密钥管理
    • 存储在环境变量或安全的密钥管理服务中
    • 定期轮换密钥
    • 不同用途使用不同密钥
  4. 使用 HTTPS:传输层加密
  5. 日志清理:不要记录敏感数据
  6. 备份安全:加密备份文件

选择哪种方案取决于你的需求:

  • 无需解密 → 哈希(password_hash)
  • 需要解密 → AES 对称加密
  • 多方共享 → RSA 非对称加密
  • 数据完整性验证 → HMAC

抱歉,评论功能暂时关闭!