首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 安全隱患:register_globals=On 導致全局變量覆蓋攻擊與防範

     編輯:PHP 相關知識

漏洞原理

當 register_globals = On 時,PHP 會將 $_GET、$_POST、$_COOKIE 等超全局數組中的鍵值自動註冊為全局變量。攻擊者可通過 URL 參數覆蓋任意全局變量 (包括 $GLOBALS、配置變量、對象屬性)。

攻擊演示

<?php
// config.php
$GLOBALS['db_host'] = 'localhost';
$GLOBALS['db_user'] = 'root';
$GLOBALS['db_pass'] = 'secret';

// index.php
require 'config.php';
// 正常邏輯使用 $GLOBALS['db_host'] 連接數據庫

攻擊請求:https://example.com/index.php?GLOBALS[db_host]=attacker.com&GLOBALS[db_user]=hacker

結果:$GLOBALS['db_host'] 被覆蓋為 attacker.com,導致連接被劫持、配置竄改、甚至繞過權限檢查。

WordPress 級防護代碼 (wp_unregister_GLOBALS)

function unregister_globals() {
    // 1. 未開啟則無需處理
    if (!ini_get('register_globals')) return;

    // 2. 檢測 GLOBALS 覆蓋嘗試
    if (isset($_REQUEST['GLOBALS']) || isset($_FILES['GLOBALS'])) {
        die('GLOBALS overwrite attempt detected');
    }

    // 3. 不應被銷毀的超全局變量
    $noUnset = ['GLOBALS', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES'];

    // 4. 合併所有輸入源
    $input = array_merge(
        $_GET, $_POST, $_COOKIE, $_SERVER, $_ENV, $_FILES,
        isset($_SESSION) && is_array($_SESSION) ? $_SESSION : []
    );

    // 5. 遍歷銷毀被註冊的全局變量
    foreach ($input as $key => $val) {
        if (!in_array($key, $noUnset) && isset($GLOBALS[$key])) {
            $GLOBALS[$key] = null;
            unset($GLOBALS[$key]);
        }
    }
}

// 在項目入口文件 (index.php) 最開頭調用
unregister_globals();

現代 PHP 最佳實踐

  1. PHP 5.4+ 已移除 register_globals: 無需擔心,但老代碼遷移時需檢查是否依賴此特性。
  2. 禁用全局變量依賴: 統一使用 $_GET、$_POST、$_SESSION 等超全局數組。
  3. 配置文件返回數組: return ['host' => '...'];,而非設置 $GLOBALS。
  4. 啟用錯誤報告: error_reporting(E_ALL); ini_set('display_errors', 0); 生產環境記錄日誌不顯示。
  5. 輸入過濾: 使用 filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) 替代直接變量。

檢測腳本

<?php
// check_globals.php - 放在項目根目錄訪問一次
if (ini_get('register_globals')) {
    echo "<h1 style='color:red'>⚠️ 危險:register_globals = On</h1>";
    echo "<p>請立即在 php.ini 中設置 register_globals = Off 並重啟 PHP。</p>";
    // 嘗試演示漏洞
    if (isset($_GET['test'])) {
        $GLOBALS['test_var'] = 'original';
        echo "<p>注入前: {$GLOBALS['test_var']}</p>";
        // 訪問 ?test=1&test_var=hacked
        echo "<p>注入後: {$GLOBALS['test_var']}</p>";
    }
} else {
    echo "<h1 style='color:green'>✅ 安全:register_globals = Off</h1>";
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved