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

打造高安全性 PHP 網站的 5 大實戰鐵律

     編輯:PHP 綜合知識

前言

PHP 以部署容易、生態豐富成為 Web 開發主流,但其鬆綁的語法特性也讓新手易寫出不安全代碼。本文歸納 5 項必須落實的安全實務,涵蓋錯誤報告、環境設定、輸入驗證、XSS 與 SQL 注入防禦,助你建立纏深防禦體系。

鐵律一:錯誤報告分級管理

開發環境:開啟完整錯誤回報,作為除錯與漏洞掃描工具。

// 開發/測試環境
error_reporting(E_ALL);
ini_set('display_errors', '1');
ini_set('log_errors', '1');
ini_set('error_log', __DIR__ . '/logs/php_error.log');

正式環境:關閉畫面顯示,僅記錄日誌,避免洩露路徑、資料庫結構等敏感資訊。

// 正式環境
error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT);
ini_set('display_errors', '0');
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php/php_error.log');

原則:使用者看不到任何 PHP 錯誤訊息,開發者能在日誌完整追蹤。

鐵律二:禁用危隬 PHP 歷史遺留特性

以下指令在 PHP 5.4+ 已移除,但舊專案或舊主機可能仍開啟,務必確認關閉:

指令危害建議值
register_globals自動將 GET/POST/COOKIE 變為全域變數,極易造成變數覆蓋與注入Off
magic_quotes_gpc自動加反斜線,導致雙重轉義、資料汙染,且給開發者虛假安全感Off
magic_quotes_runtime執行期從外部資源讀取資料時自動轉義Off
magic_quotes_sybase以雙單引號替代反斜線Off

設定方式(php.ini 優先,.htaccess 次之):

; php.ini
register_globals = Off
magic_quotes_gpc = Off
magic_quotes_runtime = Off
magic_quotes_sybase = Off

鐵律三:嚴格驗證與過濾所有使用者輸入

白名單驗證:只允許預期格式,拒絕其他。

// 範例:驗證電子郵件
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
if ($email === false) {
    throw new InvalidArgumentException('Email 格式錯誤');
}

// 範例:驗證整數 ID
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, [
    'options' => ['min_range' => 1, 'max_range' => 1000000]
]);
if ($id === false || $id === null) {
    http_response_code(400);
    exit('無效的 ID');
}

輸出編碼:根據輸出語境編碼,而非輸入時過度過濾。

  • HTML 語境:htmlspecialchars($str, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')
  • JavaScript 語境:json_encode($str)(含標籤)
  • URL 參數:urlencode($str)
  • Shell 指令:escapeshellarg($str) / escapeshellcmd($str)

鐵律四:徹底防禦跨站腳本攻擊 (XSS)

核心原則:永遠不信任使用者輸入,輸出時才根據語境編碼。

<?php
// 錯誤示範:直接輸出
echo "<div>{$_GET['msg']}</div>";

// 正確示範:HTML 語境編碼
$msg = htmlspecialchars($_GET['msg'] ?? '', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
echo "<div>{$msg}</div>";

// 若需允許有限 HTML(如部落格編輯器),請使用 HTML Purifier
require_once 'HTMLPurifier.auto.php';
$config = HTMLPurifier_Config::createDefault();
$purifier = new HTMLPurifier($config);
$cleanHtml = $purifier->purify($dirtyHtml);

HTTP 標頭加強:

// 防止瀏覽器 MIME 嗅探
header('X-Content-Type-Options: nosniff');
// 啟用瀏覽器內建 XSS 過濾器 (舊版瀏覽器)
header('X-XSS-Protection: 1; mode=block');
// 內容安全政策 (CSP) - 現代瀏覽器最強防線
header("Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;");

鐵律五:參數化查詢杜絕 SQL 注入

錯誤寫法(字串拼接):

$sql = "SELECT * FROM users WHERE username = '" . $_POST['username'] . "' AND password = '" . md5($_POST['password']) . "'";

正確寫法(PDO 預處理):

$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");
$stmt->execute([$_POST['username'], password_hash($_POST['password'], PASSWORD_DEFAULT)]);
$user = $stmt->fetch();

進階防護**:

  • 資料庫帳號最小權限:Web 連線帳號僅需 SELECT, INSERT, UPDATE, DELETE,禁止 DROP, ALTER, GRANT。
  • 錯誤訊息不回顯:正式環境關閉 display_errors,避免洩露 SQL 結構。
  • 使用 ORM/Query Builder(如 Laravel Eloquent、Doctrine)進一步抽象化 SQL。

加分項:纏深防禦清單

層面措施
Sessionsession.cookie_httponly=1, session.cookie_secure=1 (HTTPS), session.use_strict_mode=1
檔案上傳驗證 MIME、副檔名、大小;儲存於非公開目錄;重新命名;禁用腳本執行權限
CSRF所有狀態改變請求 (POST/PUT/DELETE) 需驗證 CSRF Token
密碼儲存僅用 password_hash() + password_verify(),禁止 MD5/SHA1
目錄權限遵循最小權限:目錄 755,檔案 644,上傳目錄 755 但禁用 PHP 執行
禁用函式disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source,dl,...

總結

安全非一次性工作,而是持續的流程。落實「錯誤分級、禁用歷史遺毒、白名單驗證、語境編碼輸出、參數化查詢」五大鐵律,再疊加纏深防禦層,即能阻擋 99% 以上常見攻擊。記住:沒有絕對安全,只有不斷減少攻擊面。

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