| 類型 | 典型路徑 | 生命週期 | 風險等級 |
|---|---|---|---|
| 上傳文件 | /tmp/phpXXXXXX | 請求結束自動刪除 | 🔴 高 |
| Session 文件 | /var/lib/php/sess_ | GC 清理 (默認 24 分鐘) | 🔴 高 |
| 緩存/中間文件 | /tmp/app_*, /dev/shm/ | 業務邏輯控制 | 🟡 中 |
| 編輯器備份 | ~/.*swp, .bak | 手動/編輯器管理 | 🟢 低 |
/tmp,權限通常 1777 (sticky bit),僅防刪除,**不防讀取**spellcheck46) 導致遍歷讀取他人數據.php 到 /tmp,若 Web 根目錄配置不當或包含漏洞,可觸發執行include '/tmp/upload_123.php'; 類邏輯極度危險tempnam() 返回名稱到 fopen() 之間,攻擊者可建立同名符號鏈接指向敏感文件第 2 層:最小權限創建
$fp = fopen($tempName, 'c+b'); // 創建/打開二進制讀寫,不截斷 if ($fp) { // 立即設置權限 0600 (僅擁有者讀寫) fchmod($fp, 0600); // 可選:獲取文件描述符傳遞給子進程,避免路徑暴露 }第 3 層:寫入前驗證空文件 (防劫持)
if (filesize($tempName) !== 0) { // 文件非空,可能被搶佔 unlink($tempName); throw new RuntimeException('Temp file hijacked'); } fwrite($fp, $data);第 4 層:完整性校驗 (防篡改)
// 寫入後計算哈希存入 Session/Redis $hash = hash_file('sha256', $tempName); $_SESSION['temp_hash'][$tempName] = $hash; // 後續讀取前驗證 if (hash_file('sha256', $tempName) !== $_SESSION['temp_hash'][$tempName]) { throw new RuntimeException('Temp file tampered'); }第 5 層:上傳文件專用驗證
// ✅ 必須使用 is_uploaded_file + move_uploaded_file $tmpName = $_FILES['avatar']['tmp_name']; if (!is_uploaded_file($tmpName)) { die('Invalid upload'); } // 移動到業務目錄 (跨分區複製+刪除,原子性更好) $dest = '/var/www/uploads/' . bin2hex(random_bytes(16)) . '.png'; if (!move_uploaded_file($tmpName, $dest)) { die('Move failed'); } // 設置權限 chmod($dest, 0644);第 6 層:系統級加固
php_admin_value[upload_tmp_dir] = /var/www/tmp_pool1,掛載 noexec,nosuid,nodev 的 tmpfsopen_basedir = /var/www:/tmp/php_sessionauditd 監控 /tmp 敏感操作sys_get_temp_dir() + random_bytes() + 0600 權限is_uploaded_file + move_uploaded_fileregister_shutdown_function 兜底清理grep -r "tempnam\|tmpfile\|sys_get_temp_dir" --include="*.php"臨時文件雖小,牽一髮而動全身。將「不信任文件系統」原則貫穿始終,構建零信任的臨時文件處理流程。