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

CodeIgniter 核心剖析:Input 類輸入數據安全處理全景

     編輯:PHP 相關知識

前言

「永遠不要信任用戶輸入」是 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() 執行核心清理流程。

核心清理流程:_sanitize_globals()

1. 銷毀非保護全局變量(模擬 register_globals=Off)

遍歷 $_GET、$_POST、$_COOKIE,將鍵名不在白名單(_SERVER、_GET、_POST、_FILES、_REQUEST、_SESSION、_ENV、GLOBALS、框架保留變量)中的變量從全局符號表移除($$key = NULL)。這有效防止了 register_globals 開啟時的變量注入攻擊。

2. $_GET 處理

  • 若 _allow_get_array=FALSE:直接 $_GET = []。
  • 否則:對每個鍵值調用 _clean_input_keys()(鍵名合法性)與 _clean_input_data()(值清理)。

3. $_POST / $_COOKIE 清理

同樣應用鍵名與值清理。Cookie 額外移除 RFC 2109 定義的特殊鍵($Version、$Path、$Domain),避免觸發「Disallowed Key Characters」報錯。

4. PHP_SELF 安全化

$_SERVER['PHP_SELF'] = strip_tags($_SERVER['PHP_SELF']) 防止 XSS 反射攻擊。

5. CSRF 驗證

若啟用且非 CLI 請求,調用 $this->security->csrf_verify() 驗證令牌。

數據清理核心:_clean_input_data()

遞歸處理數組/標量,步驟嚴格有序:

  1. Magic Quotes 兼容:PHP < 5.4 且 get_magic_quotes_gpc() 時 stripslashes()。
  2. UTF-8 清理:啟用 UTF8_ENABLED 時調用 $this->uni->clean_string() 移除非法字節序列。
  3. 控制字符移除:remove_invisible_characters() 消除不可见字符(如 \x00)。
  4. XSS 過濾:_enable_xss=TRUE 時調用 Security::xss_clean()(基於 HTMLPurifier 風格的黑名單/白名單混合策略)。
  5. 換行標準化:_standardize_newlines=TRUE 將 \r\n、\r 統一為 PHP_EOL。

鍵名驗證:_clean_input_keys()

if (!preg_match("/^[a-z0-9:_\/-]+$/i", $str)) {
    exit('Disallowed Key Characters.');
}

僅允許字母數字、下劃線、冒號、斜杠、連字符。過於嚴格可能誤攔正常鍵名(如帶方括號的表單數組 items[0][name]),實際項目常需調整正則或關閉全局清理改用手動 $this->input->post('key', TRUE)。

統一獲取接口:_fetch_from_array()

所有公開方法(get()、post()、cookie()、server()、get_post())最終委託此私有方法:

  • 鍵不存在 → 返回 FALSE。
  • $xss_clean=TRUE → 調用 Security::xss_clean() 二次過濾(即使全局已開啟)。
  • $index=NULL 且數組非空 → 返回整個清理後數組(get()/post() 支持)。

IP 地址獲取與驗證:ip_address() / valid_ip()

代理感知邏輯

  1. 讀取配置 proxy_ips(信任代理 IP 列表)。
  2. 按優先級檢查頭部:HTTP_X_FORWARDED_FOR、HTTP_CLIENT_IP、HTTP_X_CLIENT_IP、HTTP_X_CLUSTER_CLIENT_IP。
  3. 取首個 IP(鏈中第一個為客戶端真實 IP),驗證格式合法性。
  4. 若該 IP 合法且 REMOTE_ADDR 在信任代理列表中 → 採納該 IP;否則回退 REMOTE_ADDR。
  5. 最終 valid_ip() 二次驗證,失敗返回 0.0.0.0。

IP 格式驗證

  • 優先使用 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')。

最佳實踐建議

  1. 關閉全局 XSS 過濾:$config['global_xss_filtering'] = FALSE,改用輸出時上下文編碼(HTML/JS/URL/CSS)+ 入口業務驗證。
  2. 啟用 CSRF 保護:$config['csrf_protection'] = TRUE,表單包含 。
  3. 代理環境配置 proxy_ips:CDN/LB 後必須設置,否則 ip_address() 返回代理 IP。
  4. 鍵名正則受限時:改用 $this->input->post(NULL, TRUE) 獲取整個清理後 POST 數組,再自行處理特殊鍵名。

總結

CI_Input 是一個「重裝備、強約束」的輸入層:通過全局清理、鍵名白名單、分層 XSS 過濾、代理感知 IP 解析、CSRF 內置驗證,構建了纵深防御體系。雖然部分策略(如全局 XSS、嚴格鍵名)在現代開發中顯得保守,但其架構思想——「在框架入口統一攔截、標準化、審計所有外部輸入」——依然是構建安全 PHP 應用的基石。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved