
为什么字体也要防盗链
图片防盗链大家都知道,字体常常被忘掉。但字体文件并不小——一个完整的 woff2 中文字库动辄几百 KB 到数 MB,别人引用你的字体,走的是你的流量、你的服务器。
判断有没有被盗用,看访问日志里字体请求的 Referer 即可:
grep -E '\.(woff2?|ttf|otf|eot)' /www/wwwlogs/example.com.log
| awk '{print $11}' | sort | uniq -c | sort -rn | head -20
$11 是请求行前的 Referer 位置(按 nginx 默认日志格式)。如果里面出现一堆不是你域名的站,那就是被白嫖了。
一、规则怎么写
在站点配置里加一段:
location ~* \.(woff2?|ttf|otf|eot)$ {
valid_referers none blocked example.com www.example.com *.example.com;
if ($invalid_referer) {
add_header Cache-Control "no-store" always;
return 403;
}
}
逐段解释:
| 部分 | 作用 |
|---|---|
valid_referers | 列出允许的来源。none = 没有 Referer 头的请求(直接打开、部分客户端);blocked = Referer 被匿名化(如 https 降级或隐私模式);后面是你自己的域名 |
$invalid_referer | nginx 内置变量,Referer 不在白名单里时为真 |
return 403 | 直接拒绝 |
add_header Cache-Control "no-store" always | 关键:防止这个 403 被 CDN 或浏览器缓存住,否则以后正常访客也可能一直拿 403 |
二、两个必须注意的点
① 一定要带 none
不带 none 的话,那些不发送 Referer 的合法请求(比如用户直接粘贴字体地址、某些 APP 内置浏览器)也会被 403。这不是矫情——排障时你自己用 curl 测就会踩到。
② 只放行自己的域名,别图省事写通配
valid_referers * 等于没做。同理,如果你的站点有多个域名(主域 + 别名域),要逐个列全,漏了会出现"某个域名访问时样式错乱"这种很难查的问题。
三、验证方法
一条命令两个方向:
# 期望 403:带一个别人的 Referer
curl -s -o /dev/null -w '%{http_code}\n'
-e 'https://别人的站.com/' https://www.example.com/wp-content/themes/x/fonts/a.woff2
# 期望 200:不带 Referer(浏览器直接访问的情形)
curl -s -o /dev/null -w '%{http_code}\n'
https://www.example.com/wp-content/themes/x/fonts/a.woff2
如果第二条也返回 403,说明白名单漏了 none。
字体文件路径因主题而异,从首页源码里找
.woff2的实际地址来测最准。
四、别忘了一件事:规则顺序
nginx 的 location 匹配有优先级:= 精确 → ^~ 前缀 → 正则 ~(按配置文件里的出现顺序) → 普通前缀。所以这段正则 location 如果和别的正则 location 冲突,谁在前面谁生效。
最稳妥的做法:把这类安全/防盗规则放在一个独立文件里,用前缀(比如 00-)保证它排在最前,而不是直接塞进 vhost 主体——这样面板重新生成 vhost 时也不会被覆盖。
五、回滚
删掉这段 location(或整个独立配置文件),nginx -t && nginx -s reload 即可。正常情况下页面不会有任何变化——只有原本被盗用的流量会被切断。
一句话总结:字体防盗链和图片防盗链一个道理,但更容易被忽略,因为字体往往在主题目录里、不在你的图床清单上。写规则时记住两点:必须带 none,403 必须带 no-store。

评论 (0)