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

PHP 安全配置完整指南:從 Web 伺服器到程式碼層面的多層防護

     編輯:PHP 綜合知識

PHP 安全不僅是設定幾個 php.ini 選項,而是一套從作業系統、Web 伺服器、PHP 執行環境、資料庫到應用程式碼的多層防護體系。本文系統整理 PHP 核心安全配置、常見漏洞類型與防禦措施、現代最佳實踐,協助建立纵深防禦架構。

第一層:Web 伺服器與作業系統層面

Apache 安全強化

  • chroot 獄環境:將 Apache 限制在獨立目錄樹,即使被攻破也無法存取系統關鍵檔案。需注意:MySQL 連線需改用 127.0.0.1 (TCP) 而非 localhost (Socket),郵件發送需在 chroot 內配置 sendmail。
  • 最小權限原則:Apache 以專用低權限使用者(如 www-data)執行,嚴禁 root。
  • 模組最小化:僅載入必要模組,移除 mod_info、mod_status、mod_autoindex 等洩漏資訊的模組。
  • 隱藏版本資訊:
    ServerTokens Prod
    ServerSignature Off
  • 禁用危險指令:
    
        Options -Indexes -Includes -ExecCGI
        AllowOverride None
        Require all denied
    

Nginx + PHP-FPM 架構(現代主流)

  • PHP-FPM 以獨立使用者/群組執行,配合 listen.owner/listen.group/listen.mode 控制 Socket 權限
  • 每個站點/應用使用獨立 Pool,隔離資源與權限
  • security.limit_extensions = .php 防止非 .php 檔案被解析
  • 上傳目錄關閉 PHP 解析:
    location /uploads/ {
        location ~ \.php$ { return 403; }
    }

第二層:PHP 核心配置 (php.ini)

關鍵安全選項

上傳安全配置

file_uploads = On
upload_max_filesize = 10M
post_max_size = 12M
max_file_uploads = 20
upload_tmp_dir = /var/www/tmp_upload/  # 專用目錄,open_basedir 內
; 確保上傳目錄不可執行 PHP(見 Nginx/Apache 設定)

第三層:應用程式碼防禦(核心)

1. 變數注入與注入攻擊防禦

  • SQL 注入:全面使用預處理語句
    <?php
    // 錯誤寫法
    $sql = "SELECT * FROM users WHERE id = $id";
    
    // 正確寫法:PDO 預處理
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->execute([$id]);
    $user = $stmt->fetch();
    
    // 正確寫法:MySQLi 預處理
    $stmt = $mysqli->prepare("SELECT * FROM users WHERE id = ?");
    $stmt->bind_param("i", $id);
    $stmt->execute();
  • XSS (跨站腳本):輸出時根據上下文編碼
    <?php
    // HTML 內容
    echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
    
    // HTML 屬性
    echo htmlspecialchars($attr, ENT_QUOTES, 'UTF-8');
    
    // JavaScript 字串
    echo json_encode($js_var); // 自動處理引號、換行、Unicode
    
    // URL 參數
    echo urlencode($param);
    
    // CSS 值
    // 需專用 CSS 編碼函數
  • 命令注入:避免 exec() 等,若必須用 escapeshellarg()/escapeshellcmd()
    $arg = escapeshellarg($user_input);
    exec("convert $arg output.png");
  • 路徑遍歷:basename() + realpath() 驗證在允許目錄內

2. 檔案上傳安全處理

<?php
function secure_upload($file_array, $allowed_types, $max_size, $dest_dir) {
    // 1. 基本檢查
    if ($file_array['error'] !== UPLOAD_ERR_OK) throw new Exception('上傳錯誤');
    if ($file_array['size'] > $max_size) throw new Exception('檔案過大');
    
    // 2. MIME 類型驗證(不要信任 $_FILES['type'])
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mime = $finfo->file($file_array['tmp_name']);
    if (!in_array($mime, $allowed_types)) throw new Exception('檔案類型不允許');
    
    // 3. 副檔名白名單
    $ext = strtolower(pathinfo($file_array['name'], PATHINFO_EXTENSION));
    $allowed_ext = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
    if (!in_array($ext, $allowed_ext)) throw new Exception('副檔名不允許');
    
    // 4. 圖片二次驗證(防偽裝腳本)
    if (str_starts_with($mime, 'image/')) {
        $img_info = getimagesize($file_array['tmp_name']);
        if (!$img_info) throw new Exception('非有效圖片');
        // 可選:重新編碼圖片移除潛在惡意內容
        // imagejpeg(imagecreatefromjpeg($tmp), $dest);
    }
    
    // 5. 安全檔名:隨機名稱 + 正確副檔名
    $safe_name = bin2hex(random_bytes(16)) . '.' . $ext;
    $dest_path = $dest_dir . '/' . $safe_name;
    
    // 6. 移動檔案
    if (!move_uploaded_file($file_array['tmp_name'], $dest_path)) {
        throw new Exception('檔案移動失敗');
    }
    
    // 7. 設定檔案權限:不可執行
    chmod($dest_path, 0644);
    
    return $safe_name;
}

3. Session 安全管理

<?php
// 登入時重新產生 Session ID(防 Session Fixation)
session_regenerate_id(true);

// 設定自訂 Session 儲存處理器(Redis、資料庫)避免預設檔案儲存的併發與安全問題
// php.ini: session.save_handler = redis; session.save_path = "tcp://127.0.0.1:6379"

// 敏感操作前驗證 CSRF Token
if (!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'] ?? '')) {
    exit('CSRF 驗證失敗');
}

// 產生 CSRF Token
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));

4. 密碼儲存與驗證

<?php
// 註冊:使用 password_hash (預設 bcrypt, cost 10)
$hash = password_hash($password, PASSWORD_DEFAULT); // 或 PASSWORD_ARGON2ID
// 儲存 $hash 到資料庫

// 登入驗證
if (password_verify($input_password, $db_hash)) {
    // 成功
    // 檢查是否需重新雜湊(演算法升級、cost 增加)
    if (password_needs_rehash($db_hash, PASSWORD_DEFAULT)) {
        $new_hash = password_hash($input_password, PASSWORD_DEFAULT);
        // 更新資料庫
    }
}

// 絕對禁止:md5、sha1、自訂雜湊、明文、可逆加密

第四層:資料庫與網路層面

  • 最小權限資料庫帳號:應用程式布號僅擁有必要資料表的 SELECT/INSERT/UPDATE/DELETE,無 DROP/ALTER/GRANT 權限
  • 參數化查詢:杜絕字串拼接 SQL
  • 資料庫連線加密:MySQL SSL/TLS 連線
  • Web 應用防火牆 (WAF):ModSecurity (Apache/Nginx) 或雲端 WAF (Cloudflare, AWS WAF)
  • 速率限制:Nginx limit_req_zone、PHP 中間體、應用層 Token Bucket

現代安全開發檢查清單

指令建議值說明
expose_phpOff隱藏 HTTP 標頭 X-Powered-By: PHP/x.y.z
display_errorsOff生產環境不顯示錯誤,避免洩漏路徑、SQL、堆疊追蹤
log_errorsOn錯誤寫入日誌檔
error_log/var/log/php/error.log指定專用日誌路徑,權限 640 擁有者 www-data
error_reportingE_ALL & ~E_DEPRECATED & ~E_STRICT記錄所有錯誤但排除棄用警告
register_globalsOffPHP 5.4+ 已移除,舊版必須關閉
allow_url_fopenOff禁止 include('https://...')、fopen('https://...') 遠端檔案包含
allow_url_includeOff嚴禁遠端檔案包含(RFI 攻擊主要向量)
open_basedir/var/www/:/tmp/限制 PHP 檔案操作路徑,防止目錄遍歷讀取 /etc/passwd
disable_functionsexec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,pcntl_exec,禁用命令執行與高風險函數,視應用需求調整
disable_classesPHP 5.3+ 可禁用危險類別
session.cookie_httponly1防止 JavaScript 竊取 Session ID (XSS 緩解)
session.cookie_secure1僅 HTTPS 傳送 Cookie(需全站 HTTPS)
session.use_strict_mode1拒絕未初始化的 Session ID(防 Session Fixation)
session.gc_maxlifetime1440Session 過期時間(秒),配合 GC 機制
項目檢查點工具/驗證方式
依賴管理Composer 套件無已知漏洞composer audit、Snyk、Dependabot
靜態分析程式碼無明顯安全缺陷PHPStan (Level 5+)、Psalm、RIPS
動態掃描運行時無注入、XSS、CSRFOWASP ZAP、Burp Suite
依賴更新定期更新 PHP、擴充套件、框架composer outdated、安全公告訂閱
日誌監控錯誤、攻擊嘗試、異常存取被記錄並告警ELK、Graylog、Fail2ban
備份與恢復資料庫、檔案、配置定期備份並演練恢復自動化備份腳本、定期恢復測試
HTTPS 強制全站 HTTPS、HSTS、Secure CookieSSL Labs 測試、Security Headers 檢查
安全標頭CSP、X-Frame-Options、Referrer-Policy 等securityheaders.com

總結:纵深防禦策略

  1. 網路層:WAF、DDoS 保護、速率限制、HTTPS 強制
  2. 伺服器層:最小權限、chroot/容器隔離、模組最小化、檔案權限
  3. PHP 執行層:php.ini 硬化、禁用危險函數、open_basedir、Session 安全
  4. 應用層:參數化查詢、輸出編碼、輸入驗證、CSRF 保護、安全上傳、密碼雜湊
  5. 資料層:最小權限帳號、加密連線、敏感資料加密儲存、審計日誌
  6. 運維層:漏洞掃描、依賴更新、日誌監控、事件回應、備份演練

安全是一個持續的過程,而非一次性的設定。建立多層防護、自動化檢測、快速回應機制,才能在持續演進的威脅環境中保護 PHP 應用安全。

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