瀏覽器請求資源時自動附加 `Referer` 標頭 (來源頁面 URL)。伺服器解析 `Referer` 域名,若非自有域名則拒絕服務 (返回 403/重導向)。
<!DOCTYPE html>
<html><head>
<meta charset="gb2312">
<title>防盜鏈測試</title>
</head><body>
<form action="check.php" method="post">
提交資訊:<input type="text" name="name">
<input type="submit" name="submit" value="提交">
</form>
</body></html>
<?php
// 解析 Referer
$referer = $_SERVER['HTTP_REFERER'] ?? '';
$parsed = parse_url($referer);
echo "<pre>";
print_r($parsed);
echo "Referer: $referer";
echo "</pre>";
// 核心驗證:域名比對
$allowedHost = 'localhost'; // 生產環境改為實際域名,如 'example.com'
if (empty($parsed['host']) || $parsed['host'] !== $allowedHost) {
// 非法來源:返回錯誤並重導向
header('HTTP/1.1 403 Forbidden');
echo "<script>alert('來源驗證失敗,禁止存取'); location.href='index.php';</script>";
exit;
}
// 合法來源:繼續業務邏輯
echo "驗證通過,處理表單資料...";
print_r($_POST);
?>
<?php
$allowedHosts = ['example.com', 'www.example.com', 'api.example.com', 'localhost'];
$host = $parsed['host'] ?? '';
if (!in_array($host, $allowedHosts)) {
// 記錄可疑存取
error_log("[ANTI_LEECH] Blocked: $referer from IP: {$_SERVER['REMOTE_ADDR']}");
header('HTTP/1.1 403 Forbidden');
exit('Access Denied');
}
?>
<?php
function isHostAllowed($host, $patterns) {
foreach ($patterns as $pattern) {
// 支援 *.example.com 寫法
$regex = '/^' . str_replace('\*', '.*', preg_quote($pattern, '/')) . '$/i';
if (preg_match($regex, $host)) return true;
}
return false;
}
$allowedPatterns = ['*.example.com', 'api.partner.com'];
if (!isHostAllowed($parsed['host'] ?? '', $allowedPatterns)) {
exit('Forbidden');
}
?>
| 策略 | 適用場景 | 風險 |
|---|---|---|
| 允許空 Referer | 直接訪問、書籤、郵件連結、部分防火牆/代理過濾 | 繞過防盜鏈 |
| 拒絕空 Referer | 高安全性資源 (付費內容、API) | 誤傷正常用戶 |
| Token 驗證 | 最安全:頁面生成時植入 Token,請求攜帶 Token 驗證 | 實作複雜度較高 |
# Nginx
location ~* \.(jpg|png|gif|css|js|pdf)$ {
valid_referers none blocked *.example.com example.com;
if ($invalid_referer) {
return 403;
# 或重導向預設圖片
# rewrite ^/ https://example.com/images/nohotlink.png;
}
}
# Apache .htaccess
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteRule \.(jpg|png|gif|css|js)$ - [F,NC]