危險程式碼分析
<?php
function myAddslashes($string, $force = 0) {
!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
if (!MAGIC_QUOTES_GPC || $force) {
if (is_array($string)) {
foreach ($string as $key => $val) {
$string[$key] = myAddslashes($val, $force);
}
} else {
$string = addslashes($string);
}
}
return $string;
}
// 將 $_GET/$_POST/$_COOKIE 直接註冊為全域變數 $var
foreach (['_COOKIE', '_POST', '_GET'] as $_request) {
foreach ($$_request as $_key => $_value) {
if ($_key{0} !== '_') { // 略過 _ 開頭
$$_key = myAddslashes($_value);
}
}
}
echo $urls; // 直接使用 $urls 變數
?>
三大風險
- 變數覆蓋攻擊:攻擊者傳送 `?GLOBALS[foo]=bar` 或 `?_SESSION[admin]=1` 覆蓋超全域陣列 (PHP 5.4+ `register_globals` 已移除,但此碼手動模擬同樣效果)
- 注入繞過:`addslashes()` **非**資料庫防注入方案,多位元組編碼 (GBK/Big5) 可繞過,唯有**預處理語句**有效
- XSS 洞:`addslashes` 不處理 HTML 實體 (`<` `>` `&`),輸出到 HTML 仍會觸發腳本
現代正確做法
<?php
// 1. 顯式從超全域陣列取值
$name = $_GET['name'] ?? '';
$ids = $_POST['ids'] ?? [];
// 2. 資料庫:預處理語句 (PDO)
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = ?');
$stmt->execute([$name]);
// 3. HTML 輸出:htmlspecialchars
echo '<div>' . htmlspecialchars($name, ENT_QUOTES, 'UTF-8') . '</div>';
// 4. JS 輸出:json_encode
echo '<script> const name = ' . json_encode($name, JSON_HEX_TAG|JSON_HEX_APOS|JSON_HEX_QUOT|JSON_HEX_AMP) . '; </script>';
// 5. Shell 指令:escapeshellarg / escapeshellcmd
$cmd = 'convert ' . escapeshellarg($input) . ' output.png';
歷史背景補充
- `register_globals` (PHP 4.2 預設 Off, 5.4 移除) 將 EGPCS 直接註冊為全域變數,極度危險
- `magic_quotes_gpc` (5.4 移除) 自動 `addslashes` 給 GPC,造成重複逸出、編碼問題、誤導安全感
- 現代框架 (Laravel, Symfony) **完全不依賴** 這兩項,請確認 `php.ini` 已關閉