為防止敏感 PHP 檔案(如 API 端點、處理邏輯、設定檔)被直接在瀏覽器網址列輸入存取,需在入口處加入存取來源驗證。本文介紹兩種常見方案:HTTP_REFERER 檢查與常數標記驗證,並分析其優缺點與適用場景。
檢查請求標頭 Referer 是否為空或非預期來源。
<?php
$fromurl = 'https://www.example.com/'; // 導向目標
if (empty($_SERVER['HTTP_REFERER'])) {
header('Location: ' . $fromurl);
exit;
}
// 進一步可驗證 Referer 域名
$allowed = ['example.com', 'www.example.com'];
$referer_host = parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST);
if (!in_array($referer_host, $allowed)) {
header('Location: ' . $fromurl);
exit;
}
?>
| 優點 | 缺點 |
|---|---|
| 實作簡單、無需修改呼叫端 | Referer 可被瀏覽器設定、防火牆、Proxy 移除或偽造 |
| 適合簡單頁面導向保護 | 搜尋引擎爬蟲、書籤直接開啟、HTTPS→HTTP 會無 Referer |
| 無法防禦惡意偽造 Referer 的攻擊者 |
在入口檔案定義常數,受保護檔案檢查常數是否存在。
<?php
define('IN_SYS', true); // 定義存取標記
require 'config.php';
require 'core/bootstrap.php';
// ...
<?php
if (!defined('IN_SYS')) {
exit('禁止直接存取'); // 或 header('HTTP/1.1 403 Forbidden');
}
// 正常業務邏輯
?>
| 優點 | 缺點 |
|---|---|
| 極難繞過(需知道常數名稱且能在同進程定義) | 所有受保護檔案需包含檢查碼 |
| 不依賴客戶端行為,安全性高 | 單一入口架構下最有效,多入口需在各入口定義 |
| 效能影響微乎其微 | 若常數名稱洩露(如錯誤訊息),保護失效 |
<?php
// 核心檔案雙重保護
if (!defined('IN_SYS') && empty($_SERVER['HTTP_REFERER'])) {
header('HTTP/1.1 403 Forbidden');
exit('Access Denied');
}
// API 端點:驗證 Token + Referer
function verify_api_access() {
// 1. 檢查 API Token(Header 或參數)
$token = $_SERVER['HTTP_X_API_TOKEN'] ?? $_GET['token'] ?? '';
if (!validate_token($token)) return false;
// 2. 可選:檢查 Referer 白名單
$referer = $_SERVER['HTTP_REFERER'] ?? '';
if ($referer && !is_allowed_referer($referer)) return false;
return true;
}
!defined('IN_SYS')),置於檔案最頂端。403 Forbidden 或 404 Not Found,避免洩露檔案結構資訊。Referrer-Policy 標頭影響,建議明確設定 Referrer-Policy: strict-origin-when-cross-origin。單純依賴 HTTP_REFERER 並不安全,常數標記驗證 是防止 PHP 檔案直接存取的標準做法,配合單一入口架構可構建完整的存取控制體系。