「永遠不要信任用戶輸入」是 Web 安全鐵律。CodeIgniter 的 CI_Input 類作為框架的「免疫系統」,在請求生命周期極早期介入,對所有超全局數組進行標準化、過濾與安全加固。本文系統梳理其核心邏輯。
構造函數讀取三項關鍵配置:
allow_get_array → $_allow_get_array:是否保留 $_GET(默認 TRUE,CI 鼓勵 URI Segment 模式)。global_xss_filtering → $_enable_xss:是否全局自動 XSS 過濾(注意:CI 3 官方文檔已不推薦開啟,性能與誤傷風險較大)。csrf_protection → $_enable_csrf:CSRF 令牌驗證開關。同時引用全局 $SEC(Security 類實例)與 $UNI(UTF-8 工具類),並調用 _sanitize_globals() 執行核心清理流程。
遍歷 $_GET、$_POST、$_COOKIE,將鍵名不在白名單(_SERVER、_GET、_POST、_FILES、_REQUEST、_SESSION、_ENV、GLOBALS、框架保留變量)中的變量從全局符號表移除($$key = NULL)。這有效防止了 register_globals 開啟時的變量注入攻擊。
_allow_get_array=FALSE:直接 $_GET = []。_clean_input_keys()(鍵名合法性)與 _clean_input_data()(值清理)。同樣應用鍵名與值清理。Cookie 額外移除 RFC 2109 定義的特殊鍵($Version、$Path、$Domain),避免觸發「Disallowed Key Characters」報錯。
$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']) 防止 XSS 反射攻擊。
若啟用且非 CLI 請求,調用 $this->security->csrf_verify() 驗證令牌。
遞歸處理數組/標量,步驟嚴格有序:
get_magic_quotes_gpc() 時 stripslashes()。UTF8_ENABLED 時調用 $this->uni->clean_string() 移除非法字節序列。remove_invisible_characters() 消除不可见字符(如 \x00)。_enable_xss=TRUE 時調用 Security::xss_clean()(基於 HTMLPurifier 風格的黑名單/白名單混合策略)。_standardize_newlines=TRUE 將 \r\n、\r 統一為 PHP_EOL。if (!preg_match("/^[a-z0-9:_\/-]+$/i", $str)) {
exit('Disallowed Key Characters.');
}
僅允許字母數字、下劃線、冒號、斜杠、連字符。過於嚴格可能誤攔正常鍵名(如帶方括號的表單數組 items[0][name]),實際項目常需調整正則或關閉全局清理改用手動 $this->input->post('key', TRUE)。
所有公開方法(get()、post()、cookie()、server()、get_post())最終委託此私有方法:
FALSE。$xss_clean=TRUE → 調用 Security::xss_clean() 二次過濾(即使全局已開啟)。$index=NULL 且數組非空 → 返回整個清理後數組(get()/post() 支持)。proxy_ips(信任代理 IP 列表)。HTTP_X_FORWARDED_FOR、HTTP_CLIENT_IP、HTTP_X_CLIENT_IP、HTTP_X_CLUSTER_CLIENT_IP。REMOTE_ADDR 在信任代理列表中 → 採納該 IP;否則回退 REMOTE_ADDR。valid_ip() 二次驗證,失敗返回 0.0.0.0。filter_var($ip, FILTER_VALIDATE_IP, $flag)(PHP 5.2+)。_valid_ipv4() 嚴格四段、無前導零、0-255;_valid_ipv6() 支持壓縮零段 ::、IPv4 映射地址、逐段十六進制校驗。user_agent():獲取 HTTP_USER_AGENT,為空常意味爬蟲/curl/移動端。set_cookie():封裝 setcookie(),支持數組參數、配置文件默認值(前綴、域、路徑、Secure)、過期時間智能處理(負值即刪除)。request_headers():兼容 Apache apache_request_headers() 與 Nginx/PHP-FPM(解析 $_SERVER['HTTP_*']),統一鍵名格式(Content-Type 風格)。is_ajax_request():判斷 HTTP_X_REQUESTED_WITH === 'XMLHttpRequest'(注意:現代 fetch/Axios 可能不發送此頭,需前端配合)。is_cli_request():php_sapi_name() === 'cli' || defined('STDIN')。$config['global_xss_filtering'] = FALSE,改用輸出時上下文編碼(HTML/JS/URL/CSS)+ 入口業務驗證。$config['csrf_protection'] = TRUE,表單包含 。proxy_ips:CDN/LB 後必須設置,否則 ip_address() 返回代理 IP。$this->input->post(NULL, TRUE) 獲取整個清理後 POST 數組,再自行處理特殊鍵名。CI_Input 是一個「重裝備、強約束」的輸入層:通過全局清理、鍵名白名單、分層 XSS 過濾、代理感知 IP 解析、CSRF 內置驗證,構建了纵深防御體系。雖然部分策略(如全局 XSS、嚴格鍵名)在現代開發中顯得保守,但其架構思想——「在框架入口統一攔截、標準化、審計所有外部輸入」——依然是構建安全 PHP 應用的基石。