PHP 数据脱敏与加密的区别与实践

```html PHP 数据脱敏与加密的区别与实践

PHP 数据脱敏与加密的区别与实践

在 Web 开发中,保护用户隐私是开发者的基本责任。PHP 应用常需处理手机号、身份证号、邮箱等敏感数据,此时需明确区分数据脱敏数据加密——二者目标不同,适用场景迥异。

核心区别

  • 脱敏(Masking):不可逆的显示层处理,仅用于展示或日志,原始数据仍以明文/加密形式存储于数据库。如:138****1234
  • 加密(Encryption):可逆的数学变换,需密钥解密还原原始值,用于安全存储与传输(如 AES)。加密后数据仍具业务可用性。

实践示例

✅ 安全脱敏(展示用)

<?php
function maskPhone(string $phone): string
{
    return preg_replace('/^(\d{3})\d{4}(\d{4})$/', '$1****$2', $phone);
}

function maskIdCard(string $id): string
{
    return substr($id, 0, 6) . str_repeat('*', 8) . substr($id, -4);
}

echo maskPhone('13812345678');     // 输出:138****5678
echo maskIdCard('110101199003072358'); // 输出:110101********2358
?>

✅ 可逆加密(存储用)

使用 PHP 内置 openssl_encrypt(AES-256-CBC),确保密钥安全保管:

<?php
class SecureCrypto
{
    private const CIPHER = 'AES-256-CBC';
    private string $key;

    public function __construct(string $key)
    {
        // 建议从环境变量读取:$key = $_ENV['ENCRYPTION_KEY'] ?? '';
        $this->key = hash('sha256', $key, true); // 衍生固定长度密钥
    }

    public function encrypt(string $data): string
    {
        $ivlen = openssl_cipher_iv_length(self::CIPHER);
        $iv = openssl_random_pseudo_bytes($ivlen);
        $encrypted = openssl_encrypt($data, self::CIPHER, $this->key, 0, $iv);
        return base64_encode($iv . $encrypted);
    }

    public function decrypt(string $data): ?string
    {
        $decoded = base64_decode($data);
        $ivlen = openssl_cipher_iv_length(self::CIPHER);
        $iv = substr($decoded, 0, $ivlen);
        $ciphertext = substr($decoded, $ivlen);
        return openssl_decrypt($ciphertext, self::CIPHER, $this->key, 0, $iv);
    }
}

$crypto = new SecureCrypto('my-secret-key-2024');
$encrypted = $crypto->encrypt('user@example.com');
echo "密文:" . $encrypted . "\n";
echo "解密:" . $crypto->decrypt($encrypted); // user@example.com
?>
⚠️ 注意:脱敏不替代加密!日志中脱敏手机号,但数据库中应加密存储;避免对已脱敏数据重复加密;密钥严禁硬编码,建议使用环境变量+密钥管理服务(如 AWS KMS)。

总结:脱敏是“遮眼”,加密是“锁箱”。合理组合二者——数据库加密存储 + 接口/日志脱敏输出——才能兼顾安全性与合规性(如《个人信息保护法》《GDPR》要求)。

```