萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP register_globals 危險特性解析:為何必須關閉與現代替代方案

什麼是 register_globals

register_globals 是 PHP 4 時代的特性,啟用時會自動將 $_GET, $_POST, $_COOKIE, $_SESSION, $_SERVER 等超全域陣列的鍵值直接註冊為全域變數。

<?php
// 假設 URL: test.php?user=admin&pass=123
// register_globals = On 時:
echo $user; // 直接輸出 'admin' (未經 $_GET['user'])
echo $pass; // 直接輸出 '123'
?>

為何極度危險 (已棄用並移除)

  1. 變數來源模糊:無法區分變數來自 GET、POST、COOKIE、SESSION,攻擊者可透過 URL 注入任意全域變數。
  2. 覆蓋內部變數:惡意請求 ?is_admin=1 可能覆蓋程式內部 $is_admin 判斷邏輯,繞過權限檢查。
  3. 初始化變數漏洞:未初始化變數 (如 $authenticated) 可被外部直接設定為 true。
  4. 命名空間污染:全域命名空間被外部輸入佔據,導致不可預測行為。

歷史時間軸

  • PHP 4.2.0 (2002):**預設關閉** (Off)。
  • PHP 5.3.0:**棄用** 發出 E_DEPRECATED 警告。
  • PHP 5.4.0:**完全移除**,設定值無效果,啟用會報錯。

現代 PHP 正確做法

1. 顯式使用超全域陣列

<?php
// 明確來源、可追蹤、可過濾
$user = $_GET['user'] ?? '';
$pass = $_POST['pass'] ?? '';
$sessionId = $_COOKIE['PHPSESSID'] ?? '';
?>

2. 輸入過濾與驗證

<?php
// 過濾輸入
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_GET, 'age', FILTER_VALIDATE_INT, ['options' => ['min_range' => 18]]);

// 手動驗證
$name = trim($_POST['name'] ?? '');
if ($name === '') { /* 錯誤處理 */ }
?>

3. 依賴注入容器 (現代框架標準)

<?php
// Laravel/Service Container 範例
$request = app('request'); // 或注入 Request $request
$user = $request->input('user');
$validated = $request->validate([
    'email' => 'required|email',
    'age' => 'required|integer|min:18',
]);
?>

舊專案遷移檢查清單

  • [ ] 搜尋所有直接使用未定義變數的地方 (如 $id 非來自 $_GET['id'])。
  • [ ] 替換為對應超全域陣列存取。
  • [ ] 加入輸入驗證/過濾。
  • [ ] 確認 php.ini 無 register_globals = On (PHP 5.4+ 會直接報錯)。
  • [ ] 執行完整測試套件。

結語

register_globals 是 PHP 歷史上最大的設計失誤之一,已徹底移除超過十年。任何仍建議開啟此選項的教學/框架 (如舊版 ThinkPHP 1.x/2.x) 皆為過時且不安全。現代 PHP 開發請堅持:顯式輸入來源、嚴格驗證過濾、依賴注入管理相依性。

copyright © 萬盛學電腦網 all rights reserved