本文目录导读:

在 PHP 中实现“透明加密”通常有两种截然不同的理解,下面分别说明,你可以根据实际需求选择对应方案。
数据库层面的透明加密(TDE)
这是指对存入数据库的数据自动加密,读取时自动解密,业务代码无需感知。
使用 MySQL 的 TDE(表空间加密)
MySQL 5.7+ 支持 InnoDB 表空间加密:
-- 创建加密表空间 CREATE TABLESPACE ts1 ADD DATAFILE 'ts1.ibd' ENCRYPTION='Y'; -- 创建加密表 CREATE TABLE t1 (id INT, data VARCHAR(255)) TABLESPACE ts1 ENCRYPTION='Y';
PHP 代码无需任何改动。
使用扩展如 openssl 封装加解密函数
通过统一的封装函数实现透明加解密:
class TransparentCrypto {
private static $key = 'your-32-byte-secret-key';
private static $cipher = 'aes-256-gcm';
public static function encrypt($plaintext) {
$iv = random_bytes(openssl_cipher_iv_length(self::$cipher));
$tag = '';
$ciphertext = openssl_encrypt($plaintext, self::$cipher, self::$key, 0, $iv, $tag);
return base64_encode($iv . $tag . $ciphertext);
}
public static function decrypt($ciphertext) {
$data = base64_decode($ciphertext);
$ivLen = openssl_cipher_iv_length(self::$cipher);
$iv = substr($data, 0, $ivLen);
$tag = substr($data, $ivLen, 16);
$ciphertext = substr($data, $ivLen + 16);
return openssl_decrypt($ciphertext, self::$cipher, self::$key, 0, $iv, $tag);
}
}
// 使用:
$encrypted = TransparentCrypto::encrypt('敏感数据');
$decrypted = TransparentCrypto::decrypt($encrypted);
文件级的透明加密(磁盘/虚拟文件系统)
这种方案下,PHP 代码读写文件时自动加解密,通常通过 系统层面的加密文件系统 实现:
使用 GnuPG 加密文件系统
# 安装 apt-get install gnupg encfs # 创建加密目录 mkdir /encrypted /mnt/plain encfs /encrypted /mnt/plain # PHP 代码直接读写 /mnt/plain/ 下的文件即可
使用 Linux 的 dm-crypt/LUKS
对整个分区或目录进行加密,PHP 透明访问:
cryptsetup luksFormat /dev/sdb1 cryptsetup open /dev/sdb1 encrypted_partition mount /dev/mapper/encrypted_partition /var/www/encrypted_data
PHP 层面的全流程透明加密
这是指框架级的自动加解密,通过中间件或魔术方法实现:
使用 Laravel 的 Casts(Eloquent 自动转换)
// Model 中定义
class User extends Model {
protected $casts = [
'phone' => 'encrypted',
'ssn' => 'encrypted:json'
];
}
// 使用时完全透明
$user = User::find(1);
echo $user->phone; // 自动解密
$user->phone = '13800000000'; // 自动加密存储
使用 PDO 包装器
创建一个 PDO 扩展类,在预处理语句中透明处理加密字段:
class EncryptedPDO extends PDO {
private $encryptedColumns = ['phone', 'email'];
public function prepare($sql, $options = []) {
// 解析 SQL,对指定字段自动加密
return new EncryptedStatement(parent::prepare($sql), $this);
}
public function encryptValue($value) {
return TransparentCrypto::encrypt($value);
}
public function decryptValue($value) {
return TransparentCrypto::decrypt($value);
}
}
分布式文件系统加密
如果使用对象存储(如 S3、OSS),可以结合客户端加密:
use Aws\S3\S3Client;
use Aws\S3\Crypto\S3EncryptionClientV2;
$s3 = new S3Client([/* config */]);
$encryptionClient = new S3EncryptionClientV2($s3);
$result = $encryptionClient->putObject([
'Bucket' => 'bucket-name',
'Key' => 'file-key',
'Body' => 'plain text',
]);
选择建议
| 场景 | 推荐方案 |
|---|---|
| 数据库敏感字段 | ⭐ 使用 ORM 的加密 Cast(Laravel/Symfony) |
| 大量历史数据 | 数据库 TDE 或磁盘级加密 |
| 临时文件/日志 | EncFS 或 GnuPG 目录加密 |
| 云存储 | 对象存储客户端加密 |
| 高安全性要求 | 应用层加密 + 数据库 TDE 双保险 |
完整示例:一个透明的加密存储类
class SecureStore {
private static $keyPath = '/secure/keys/';
private static $dirMap = [];
public static function store($filename, $data) {
$key = self::getOrCreateKey($filename);
$encrypted = self::encryptWithKey($data, $key);
file_put_contents(self::safePath($filename), $encrypted);
// 记录加密元数据
self::saveMetadata($filename, $key);
}
public static function retrieve($filename) {
$key = self::getKey($filename);
$data = file_get_contents(self::safePath($filename));
return self::decryptWithKey($data, $key);
}
private static function getOrCreateKey($filename) {
if (!isset(self::$dirMap[$filename])) {
self::$dirMap[$filename] = random_bytes(32);
}
return self::$dirMap[$filename];
}
}
核心要点:
- 透明 意味着业务代码不感知加解密过程
- 对于数据库,优先选择 ORM 自动转换或数据库 TDE
- 对于文件,选择操作系统级别的加密文件系统
- 敏感数据一定要使用 认证加密(如 AES-GCM),防止篡改
根据你的具体使用场景(数据库、文件、API 数据传输),可以进一步细化实现方案。