防盜鏈核心在於識別請求來源,僅允許本站頁面引用靜態資源。本文對比 PHP 應用層、Apache、Nginx、IIS 多層級防盜鏈方案,幫助你選擇最適合的部署策略。
利用 $_SERVER['HTTP_REFERER'] 判斷來源,配合 Session 防止直接訪問。適合無服務器配置權限的虛擬主機環境。
<?php
// 入口文件(如 index.php)設置 Session 標記
session_start();
$_SESSION['allow_access'] = true;
?>
<?php
// 圖片輸出腳本(如 show_img.php)
session_start();
$referer = parse_url($_SERVER['HTTP_REFERER'] ?? '');
// 雙重校驗:Session 標記 + 來源域名
if (empty($_SESSION['allow_access']) || $referer['host'] !== $_SERVER['HTTP_HOST']) {
header('HTTP/1.1 403 Forbidden');
exit('Access Denied');
}
// 輸出圖片
$file = '/path/to/images/' . basename($_GET['img']);
if (is_file($file)) {
header('Content-Type: ' . mime_content_type($file));
readfile($file);
}
?>
缺點:Referer 可偽造、防火牆/代理可能剔除;PHP 處理靜態文件佔用進程,高併發下效能差。
在 .htaccess 或 httpd.conf 中配置,性能最優,無需啟動 PHP 進程。
<!-- 僅允許本站與空 Referer(直接輸入網址)訪問 -->
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?yourdomain\.com [NC]
RewriteRule \.(gif|jpg|jpeg|png|bmp|webp)$ /static/forbidden.png [R=302,L]
<!-- 進階:返回 403 而非跳轉 -->
RewriteRule \.(gif|jpg|png)$ - [F,NC]
關鍵點:
!^$ 允許無 Referer 請求(瀏覽器直接打開圖片網址),視業務決定是否保留。[NC] 大小寫不敏感匹配域名。/static/ 目錄並排除該目錄規則,避免無限循環。Nginx 原生 valid_referers 指令語義清晰,效能極高。
location ~* \.(gif|jpg|jpeg|png|bmp|webp|pdf|zip|rar)$ {
valid_referers none blocked yourdomain.com *.yourdomain.com;
if ($invalid_referer) {
return 403; # 或 rewrite /static/forbidden.png redirect;
# rewrite ^/static/forbidden.png last; # 內部跳轉避免 302
}
# 可選:緩存控制
expires 30d;
add_header Cache-Control "public";
}
none:允許無 Referer;blocked:允許被防火牆過濾的 Referer;*.yourdomain.com;在 web.config 中配置:
<rule name="AntiHotlink" stopProcessing="true">
<match url=".*\.(gif|jpg|png|pdf|zip)$" />
<conditions>
<add input="{HTTP_REFERER}" pattern="^$" negate="true" />
<add input="{HTTP_REFERER}" pattern="^https?://(www\.)?yourdomain\.com" negate="true" />
</conditions>
<action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Hotlinking not allowed" />
</rule>
對於付費資源、私有文件,Referer 檢查不夠安全。採用帶過期時間的簽名 URL:
<?php
// 生成簽名鏈接
function signedUrl($file, $expire = 300) {
$secret = 'your_secret_key';
$expireTime = time() + $expire;
$signature = hash_hmac('sha256', $file . $expireTime, $secret);
return "/download.php?file=$file&expire=$expireTime&sign=$signature";
}
// download.php 驗證
$file = $_GET['file'];
$expire = (int)$_GET['expire'];
$sign = $_GET['sign'];
if (time() > $expire) exit('Link expired');
$expected = hash_hmac('sha256', $file . $expire, 'your_secret_key');
if (!hash_equals($expected, $sign)) exit('Invalid signature');
// 輸出文件...
?>
此方案無視 Referer,適合 API、CDN 回源、私有雲場景。
| 方案 | 性能 | 安全性 | 維護成本 | 適用場景 |
|---|---|---|---|---|
| PHP Session + Referer | 低 | 低 | 低 | 虛擬主機、無服務器權限 |
| Apache mod_rewrite | 高 | 中 | 中 | Apache 環境、靜態資源防盜鏈 |
| Nginx valid_referers | 極高 | 中 | 低 | Nginx 環境、高併發靜態資源 |
| 簽名 URL (Token) | 中 | 極高 | 高 | 付費資源、私有文件、API 下載 |
生產建議:靜態資源走 Nginx/Apache 層防盜鏈,動態/私有資源用簽名 URL,雙管齊下兼顧性能與安全。