第四部分:數據淨化與安全攻防 (Sanitization & SQLi)

將「安全」從道德說教,轉化為記憶體編碼與語法樹解析的物理對抗機制。

一、 數據淨化機制 (Data Sanitization) - 防禦 XSS

前提:用戶在表單輸入的內容,可能包含 HTML 標籤或 JavaScript 代碼。如果伺服器將其原封不動輸出至網頁,瀏覽器引擎會將其視為代碼「編譯並執行」,造成跨站腳本攻擊 (XSS)。

1. 移除首尾空白字元

trim()

底層機制: 剝離字串兩端無意義的空白字元(Space)、定位字元(Tab)、換行字元(\n)。這是為了防止用戶不小心輸入空白,導致資料庫比對失敗或長度異常。

$raw_input = "   user123   ";
$clean_input = trim($raw_input);
// 結果: "user123"

2. 移除跳脫斜線

stripslashes()

底層機制: 在某些舊版 PHP 設定(Magic Quotes)中,系統會自動幫引號加上反斜線(如 \')。此函數負責將這些反斜線剝離,還原字串原本的樣貌。

$raw_input = "O\\'Reilly";
$clean_input = stripslashes($raw_input);
// 結果: "O'Reilly"

3. HTML 實體編碼 (XSS 絕對防禦)

htmlspecialchars()

物理對抗機制: 這是防禦 XSS 的核心。它會將具有「結構意義」的特殊字元,強制轉換為「顯示用」的 HTML 實體 (Entities)。
例如:將小於符號 < 轉換為 &lt;。當瀏覽器讀取到 &lt;script&gt; 時,它只會將其渲染為畫面上的文字,而絕對不會將其丟入 JS 引擎執行。它剝奪了字串的「執行權限」。

// 駭客嘗試在留言板注入惡意腳本
$hacker_input = "<script>alert('Hacked!');</script>";

// 安全的輸出方式 (過濾後再印出)
$safe_output = htmlspecialchars($hacker_input);
echo $safe_output; 
// 網頁原始碼會變成: &lt;script&gt;alert('Hacked!');&lt;/script&gt;

二、 SQL 注入 (SQL Injection) 語法樹突變

前提:當我們使用「字串拼接」的方式將用戶輸入放入 SQL 語句時,駭客可以透過輸入單引號 ' 提早閉合字串,並注入新的邏輯指令。這模糊了「數據」與「代碼」的物理邊界。

SQLi 漏洞推導與轉義防禦

mysqli_real_escape_string()
  • 漏洞推導: 假設登入檢查代碼為 "SELECT * FROM users WHERE user = '" . $_POST['user'] . "'"
    駭客輸入:' OR 1=1 --
    拼接後的 SQL 語法樹發生突變:SELECT * FROM users WHERE user = '' OR 1=1 -- '
    因為 1=1 永遠為真,且 -- 註解掉了後面的密碼檢查,駭客無需密碼即可登入。
  • 防禦機制 (轉義): mysqli_real_escape_string($conn, $input) 會在單引號等特殊字元前方加上反斜線 \'。資料庫解析器會將其視為「單純的文字引號」,而非「字串閉合指令」。
$raw_user = "' OR 1=1 -- ";

// [漏洞寫法] 直接拼接:
$sql = "SELECT * FROM accounts WHERE user = '" . $raw_user . "'";
// 引擎解析:條件被竄改,全表資料洩漏。

// [防禦寫法] 轉義後拼接:
$safe_user = mysqli_real_escape_string($conn, $raw_user);
$sql = "SELECT * FROM accounts WHERE user = '" . $safe_user . "'";
// 引擎解析:嚴格尋找帳號名稱為字面值 "' OR 1=1 -- " 的用戶,攻擊失效。

三、 網路安全攻防實驗室 (Security Lab)

選擇不同的攻擊載荷 (Payload),觀察「未經淨化 (裸奔狀態)」與「啟動 PHP 防禦函數」時,系統底層渲染與 SQL 解析的劇烈差異。

駭客終端 (Attacker Payload)
伺服器解析引擎 (Server Parser)
無防禦 (Vulnerable) - 變數直接輸出
JavaScript 執行警告
您的 Cookie 已被竊取!
(內容顯示區)
SELECT * FROM users WHERE name = '(未輸入)'
啟動防禦 (Secured) - 經過函數淨化
(內容顯示區)
SELECT * FROM users WHERE name = '(未輸入)'