PHP 文件加密上传与下载完整实现
在 Web 应用中,敏感文件(如合同、证件、日志)需防止未授权访问与中间窃取。本文提供基于 OpenSSL 的端到端加密方案:**上传时 AES-256-CBC 加密 → 存储密文 → 下载时解密返回明文**,全程不暴露密钥于客户端。核心要点
- 使用
openssl_encrypt()/openssl_decrypt()实现对称加密 - 密钥由服务端安全生成并硬编码(生产环境建议使用环境变量或密钥管理服务)
- IV(初始向量)随机生成并随密文一同存储(非保密,但必须唯一)
- 文件元信息(原名、大小、MIME)经 JSON 序列化后加密,保障完整性
1. 加密上传示例
<?php
$key = '32-byte-secret-key-for-aes-256!'; // 生产请使用 openssl_random_pseudo_bytes(32)
$uploadDir = __DIR__ . '/secure_uploads/';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file'])) {
$file = $_FILES['file'];
if ($file['error'] !== UPLOAD_ERR_OK) die('上传失败');
$iv = openssl_random_pseudo_bytes(16);
$plaintext = file_get_contents($file['tmp_name']);
// 加密文件内容
$ciphertext = openssl_encrypt($plaintext, 'AES-256-CBC', $key, 0, $iv);
// 加密元数据(原文件名 + MIME)
$meta = json_encode([
'name' => $file['name'],
'mime' => $file['type'],
'size' => $file['size']
]);
$metaEnc = openssl_encrypt($meta, 'AES-256-CBC', $key, 0, $iv);
// 保存:IV + 密文 + 加密元数据(以 | 分隔)
$filename = uniqid() . '.enc';
file_put_contents($uploadDir . $filename, $iv . '|' . $ciphertext . '|' . $metaEnc);
echo "✅ 上传成功,文件 ID:{$filename}";
}
?>
<form method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">加密上传</button>
</form>
2. 安全下载示例
<?php
$key = '32-byte-secret-key-for-aes-256!';
$uploadDir = __DIR__ . '/secure_uploads/';
if (isset($_GET['id']) && preg_match('/^[a-zA-Z0-9_-]+\.enc$/', $_GET['id'])) {
$path = $uploadDir . $_GET['id'];
if (!file_exists($path)) die('文件不存在');
$data = file_get_contents($path);
[$iv, $ciphertext, $metaEnc] = explode('|', $data, 3);
// 解密元数据
$metaRaw = openssl_decrypt($metaEnc, 'AES-256-CBC', $key, 0, $iv);
$meta = json_decode($metaRaw, true);
if (!$meta || !isset($meta['name'], $meta['mime'])) die('元数据损坏');
// 解密文件内容
$plaintext = openssl_decrypt($ciphertext, 'AES-256-CBC', $key, 0, $iv);
if ($plaintext === false) die('解密失败,请检查密钥');
// 强制下载(避免浏览器渲染敏感内容)
header('Content-Type: ' . $meta['mime']);
header('Content-Disposition: attachment; filename="' . basename($meta['name']) . '"');
header('Content-Length: ' . strlen($plaintext));
echo $plaintext;
exit;
}
?>
<a href="?id=abc123xyz.enc">⬇️ 下载加密文件</a>
⚠️ 安全提醒:
• 密钥切勿写死在代码中(生产环境使用
$_ENV['ENCRYPTION_KEY'] 或 Vault);
• 上传目录禁止 Web 直接访问(通过 .htaccess Deny from all 或 Nginx deny all;);
• 建议增加用户权限校验、文件类型白名单、大小限制及防重放机制。
通过此方案,文件在传输与存储环节全程加密,即使服务器被入侵,攻击者也无法直接读取原始内容。安全不是功能,而是贯穿设计的基石。
```