要记录被防盗链拦截的异常访问,关键在于通过$invalid_referer变量显式标记拦截状态,并按资源类型分离日志、补充referer分类,同时注意空referer等误判场景。

要记录被防盗链拦截的异常访问,关键不是只记“谁被拦了”,而是让日志能清晰区分“正常请求”和“因 referer 不合法被拦的请求”,同时避免把空 referer 或误判流量混为一谈。
在日志中显式标记拦截状态
默认 access_log 不包含拦截标识。需配合 $invalid_referer 变量,用 set 或 map 定义一个标记字段(如 $blocked),再写入自定义日志格式:
- 在 server 或 http 块中添加:
set $blocked "-";<br>if ($invalid_referer) { set $blocked "blocked"; } - 定义日志格式时加入该变量:
log_format referer_log '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$blocked"'; - 启用该格式:
access_log /var/log/nginx/referer.log referer_log;
这样每条日志末尾会显示 "-"(正常)或 "blocked"(被防盗链规则拦截),方便 grep、awk 快速筛选。
按资源类型分离日志,避免干扰
防盗链通常只作用于图片、字体等静态资源。把这类请求单独记录,能避免与首页、API 等正常流量混在一起:
- 在匹配图片后缀的 location 中启用独立日志:
location ~* \.(jpg|jpeg|png|gif|webp|ico|svg)$ {<br> valid_referers none blocked server_names *.yourdomain.com;<br> access_log /var/log/nginx/blocked-images.log referer_log;<br> if ($invalid_referer) { return 403; }<br>} - 这样所有被拦的图片请求都集中在
blocked-images.log,排查更聚焦。
补充 referer 分类,识别真实来源意图
单靠 $invalid_referer 只知道“不合法”,但不知道“来自哪”。用 map 对 $http_referer 做分类,可快速定位高频盗链域名:
- 添加 map 块(放在 http 块内):
map $http_referer $referer_type {<br> default "other";<br> "-" "direct";<br> ~*\.baidu\.com "baidu";<br> ~*\.google\.com "google";<br> ~*yourdomain\.com "internal";<br> ~*bad-site\.net "bad-site";<br>} - 将
$referer_type加入 log_format,日志中就能看到是bad-site还是direct,便于后续拉黑或白名单调整。
注意空 referer 和误判场景
微信内嵌浏览器、App WebView、HTTPS→HTTP 跳转都会导致 referer 为空("-")。若日志里大量 "blocked" 对应 "-",说明配置可能过于严格:
- 确保
valid_referers包含none,允许空 referer 访问; - 不要对空 referer 单独返回 403,除非你明确要限制书签/直连行为;
- 检查是否误将合作方域名拼错,或未加
https://前缀导致匹配失败。
不复杂但容易忽略。











