圖片、下載檔案被外站直接引用(盜鏈)會消耗頻寬、洩露資源。本文系統整理三層防禦體系:**PHP 應用層驗證(靈活但可繞過)、Apache/Nginx 伺服器層重寫(高效能、標準)、IIS 重寫模組**,並提供可直接部署的配置範例。
原理:檢查 $_SERVER['HTTP_REFERER'] 是否包含本站域名,或驗證 Session 標記。缺點:Referer 可偽造、用戶可關閉發送、代理/防火牆可能剝離。
<?php
// 入口檔案或圖片輸出腳本開頭
session_start();
$referer = parse_url($_SERVER['HTTP_REFERER'] ?? '', PHP_URL_HOST);
$allowedHosts = ['example.com', 'www.example.com', 'static.example.com'];
if (empty($referer) || !in_array($referer, $allowedHosts)) {
// 可選:返回 403、透明圖、預設圖、重導向
header('HTTP/1.1 403 Forbidden');
exit('Hotlinking not allowed');
}
// 正常輸出圖片/檔案
readfile('/path/to/real/file.jpg');
在 .htaccess 或 httpd.conf <Directory> 區塊:
# 啟用重寫引擎
RewriteEngine On
# 允許空 Referer(直接輸入網址、書籤、某些代理)
RewriteCond %{HTTP_REFERER} ^$ [OR]
# 允許本站域名(含子域名、協議)
RewriteCond %{HTTP_REFERER} ^https?://(www\.)?example\.com/ [NC]
# 允許特定合作夥伴域名(可選)
# RewriteCond %{HTTP_REFERER} ^https?://(partner\.com|api\.partner\.com)/ [NC]
# 符合上述條件者放行,否則攔截
RewriteRule \.(jpe?g|png|gif|webp|pdf|zip|rar)$ - [F,NC,L]
# 進階:返回指定防盜鏈圖片(需確保該圖不觸發規則)
# RewriteRule \.(jpe?g|png|gif)$ /images/hotlink-denied.png [R=302,NC,L]
location ~* \.(jpe?g|png|gif|webp|pdf|zip|rar)$ {
valid_referers none blocked
example.com
www.example.com
*.example.com
partner.com;
if ($invalid_referer) {
return 403; # 或 rewrite /hotlink-denied.png redirect;
# return 302 /hotlink-denied.png;
}
# 可選:添加緩存頭、防盜鏈水印
expires 30d;
add_header Cache-Control "public";
}
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Prevent Hotlinking" stopProcessing="true">
<match url=".*\.(jpe?g|png|gif|webp|pdf|zip|rar)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{HTTP_REFERER}" pattern="^$" negate="true" />
<add input="{HTTP_REFERER}" pattern="^https?://(www\.)?example\.com/" negate="true" />
</conditions>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Hotlinking not allowed" />
<!-- 或重導向到防盜鏈圖片 -->
<!-- <action type="Redirect" url="/hotlink-denied.png" redirectType="Found" /> -->
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
對於付費資源、私密檔案,Referer 驗證不足夠。採用**帶期限簽名的一次性 URL**:
// 生成簽名下載連結 (Laravel 範例)
$url = URL::temporarySignedRoute(
'download.file', now()->addMinutes(30), ['file' => $filename]
);
// 輸出:/download/file/abc123?signature=xxx&expires=1234567890
// 路由中間件自動驗證簽名與過期時間
Route::get('/download/file/{file}', 'DownloadController@download')
->name('download.file')
->middleware('signed');
優點:無 Referer 依賴、可控過期、可限制 IP/用戶、支援 CDN 邊緣驗證。
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 靜態資源(圖片、CSS、JS) | Nginx/Apache valid_referers / RewriteRule | 零 PHP 開銷、CDN 邊緣可直接執行 |
| 動態生成圖表/驗證碼 | PHP Session/Token 驗證 | 需結合業務邏輯(如登入狀態) |
| 付費/私密下載 | 簽名 URL + 伺服器層雙重校驗 | 最高安全性、可審計、支援 CDN |
| 虛擬主機無法修改伺服器配置 | PHP Referer 檢查 + .htaccess (Apache) | 唯一可行途徑 |
防盜鏈應遵循**「越前端越好、越靜態越好」**原則:優先在 Nginx/Apache/CDN 層以 valid_referers/RewriteRule 阻擋 99% 盜鏈;動態資源用 PHP Session/Token 輔助;核心付費資源務必升級為**簽名 URL**。切勿單獨依賴 HTTP_REFERER,它不可靠且易繞過。