PHP 4.2.0 以前,register_globals = On 為預設值。這意味著 ?id=123 會自動建立 $id = 123,Session 變數 $_SESSION['user'] 也能直接用 $user 存取。雖然方便,卻造成嚴重安全隱患:攻擊者可透過 URL 覆蓋內部變數(如 $is_admin=1),導致權限繞過。
PHP 4.2.0 起預設關閉 register_globals,並引入 **超全域變數** 機制:在所有作用域自動可見,無需 global 關鍵字,強制開發者明確指定資料來源。
| 超全域變數 | 舊式陣列 | 資料來源 | 典型用途 |
|---|---|---|---|
$_SERVER | $HTTP_SERVER_VARS | Web 伺服器環境與執行資訊 | $_SERVER['REQUEST_URI'], $_SERVER['HTTP_USER_AGENT'], $_SERVER['REMOTE_ADDR'] |
$_GET | $HTTP_GET_VARS | URL 查詢字串參數 | 搜尋關鍵字、分頁頁碼、篩選條件 |
$_POST | $HTTP_POST_VARS | HTTP POST 表單欄位 | 登入帳密、文章發布、API 載荷 |
$_COOKIE | $HTTP_COOKIE_VARS | 客戶端 Cookie | 記住登入、偏好設定、追蹤 ID |
$_SESSION | $HTTP_SESSION_VARS | 伺服器端 Session 儲存 | 用戶身份、購物車、CSRF Token |
$_FILES | $HTTP_POST_FILES | HTTP 檔案上傳 | 頭像上傳、附件處理、文件匯入 |
$_ENV | $HTTP_ENV_VARS | 系統環境變數 | 部署環境區分、金鑰注入(配合 Docker/K8s) |
$_REQUEST | — | $_GET + $_POST + $_COOKIE(順序受 variables_order 影響) | 不建議使用,來源模糊易植入惡意資料 |
$GLOBALS | — | 所有全域變數的參考陣列 | 極少數需動態變數名稱場景 |
假設表單欄位 name="myfile":
$_FILES['myfile'] = [
'name' => 'photo.jpg', // 客戶端原始檔名(含路徑資訊,不可信)
'type' => 'image/jpeg', // 瀏覽器回報 MIME,需伺服端二次驗證
'size' => 245760, // 檔案大小(位元組)
'tmp_name' => '/tmp/phpA1B2C3', // 伺服器暫存路徑(處理完須 move_uploaded_file 移動)
'error' => UPLOAD_ERR_OK // 錯誤碼:0=成功,1=超過 upload_max_filesize,2=超過 MAX_FILE_SIZE,3=部分上傳,4=無檔案,6=缺少暫存目錄,7=寫入失敗,8=擴展中斷
];
安全處理流程:
error === UPLOAD_ERR_OKsize 不超業務上限finfo_file() 或 mime_content_type() 驗證真實 MIMEmove_uploaded_file() 移至非 Web 可執行目錄<?php
// 直接信任 $_SERVER['PHP_SELF'] 導致 XSS
echo '<form action="' . $_SERVER['PHP_SELF'] . '">';
// 使用 $_REQUEST 混淆來源
$id = $_REQUEST['id']; // 可能來自 Cookie 覆蓋 GET
// 未驗證直接使用 $_FILES
move_uploaded_file($_FILES['f']['tmp_name'], '/var/www/uploads/' . $_FILES['f']['name']);
?>
<?php
// 表單 action 留空或用 htmlspecialchars
echo '<form action="" method="post">';
// 明確來源
$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
// 檔案上傳完整驗證
$allowed = ['image/jpeg', 'image/png', 'image/gif'];
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['f']['tmp_name']);
if ($_FILES['f']['error'] === UPLOAD_ERR_OK
&& in_array($mime, $allowed)
&& $_FILES['f']['size'] < 2 * 1024 * 1024) {
$ext = ($mime === 'image/jpeg') ? '.jpg' : (($mime === 'image/png') ? '.png' : '.gif');
$dest = '/var/www/uploads/' . bin2hex(random_bytes(16)) . $ext;
move_uploaded_file($_FILES['f']['tmp_name'], $dest);
}
?>
register_globals、register_long_arrays($HTTP_*_VARS)、magic_quotes_* 指令。$_ENV 預設不再自動填入(需 variables_order 含 E)。$_FILES['xxx']['full_path'] 新增完整路徑資訊(目錄上傳)。核心原則:輸入過濾、輸出轉義、來源明確。超全域變數只是「受管的入口」,安全性取決於你如何驗證與使用這些資料。