配置文件通常包含資料庫憑證、API 金鑰、加密鹽等極敏感資訊。若 Web 服務器配置錯誤導致 PHP 解析失效,或攻擊者直接請求 /config/config.php,將造成災難性洩露。本文提供三層防護體系:代碼級常量守衛、Web 服務器級訪問控制、架構級目錄隔離。
// public/index.php(公開目錄唯一入口)
define('APP_STARTED', true);
require_once __DIR__ . '/../app/bootstrap.php';
// app/config/database.php
if (!defined('APP_STARTED')) {
// 直接訪問時:無常量 → 終止執行
header('HTTP/1.0 403 Forbidden');
exit('Direct access forbidden');
}
// 正常邏輯
return [
'host' => 'localhost',
'user' => 'db_user',
'pass' => 'secret',
'name' => 'myapp',
];
# 放在 config/ 目錄下
Order Deny,Allow
Deny from all
# 或全域 httpd.conf
Require all denied
# 禁止訪問 config 目錄下所有 php 文件
location ~ ^/config/.*\.php$ {
deny all;
return 403;
}
# 或禁止整個 config 目錄
location /config/ {
internal; # 僅允許內部重定向(如 X-Accel-Redirect)
}
/var/www/myapp/ ├── public/ # DocumentRoot,唯一公開目錄 │ ├── index.php # 入口 │ ├── .htaccess │ └── assets/ # 靜態資源 ├── app/ # 應用代碼(Web 不可直接訪問) │ ├── config/ # 配置文件 │ ├── src/ # 業務邏輯 │ └── bootstrap.php ├── vendor/ # Composer 依賴 └── storage/ # 日誌、快取、上傳
核心原則:DocumentRoot 指向 public/,所有 PHP 邏輯、配置、依賴均在 public/ 之外,Web 服務器物理無法直接請求。
// .env(不提交版本庫,各環境獨立)
DB_HOST=localhost
DB_USER=myapp
DB_PASS=secure_random_string
APP_KEY=base64:xxxx
// config/database.php
return [
'host' => env('DB_HOST'),
'user' => env('DB_USER'),
'pass' => env('DB_PASS'),
'name' => env('DB_NAME'),
];
// env() 輔助函數
function env(string $key, $default = null) {
$value = getenv($key);
if ($value === false) return $default;
// 類型轉換
switch (strtolower($value)) {
case 'true': case '(true)': return true;
case 'false': case '(false)': return false;
case 'empty': case '(empty)': return '';
case 'null': case '(null)': return null;
}
return $value;
}
優勢:配置與代碼分離、無敏感信息入庫、環境遷移零修改、Docker/K8s 原生支援。
| 誤區 | 風險 | 正確做法 |
|---|---|---|
| 只用常量守衛 | PHP 解析失效時直接輸出源碼 | 必須配合 Web 服務器層防護 |
| 配置文件放在公開目錄 | 猜測路徑即可下載 | 移至 DocumentRoot 之外 |
| .git 包含 .env | 敏感信息洩露 | .gitignore 排除 .env,用 .env.example 模板 |
| 生產環境開啟顯示錯誤 | 錯誤堆疊洩露路徑結構 | display_errors=Off, log_errors=On |
# 1. 直接請求配置文件
curl -I https://yourdomain.com/config/database.php
# 預期:403 Forbidden 或 404 Not Found
# 2. 模擬 PHP 解析失效(臨時重命名 php-fpm socket)
# 請求任意 .php,預期不應輸出源碼
# 3. 掃描工具檢測
nikto -h yourdomain.com
配置文件防護不是單一手段能解決的,「代碼守衛 + Web 服務器封鎖 + 目錄物理隔離 + 環境變量化」四層疊加,才能構建纵深防禦。現代 PHP 專案(Laravel、Symfony、ThinkPHP 6+)均預設採用 public/ 入口隔離架構,**請勿為了「部署方便」而妥協將配置文件暴露在 Web 根目錄下**。