fiber 本身不内置防盗链功能,但可通过 referer 校验中间件实现粗粒度防护;需注意空 referer 处理、域名精确匹配、占位图直发而非重定向,并优先用 nginx 在反代层拦截。

Fiber 是 Go 语言的轻量级 Web 框架,本身不内置防盗链逻辑,但可以通过中间件 + 请求头校验轻松实现。关键不是「Fiber 有没有防盗链功能」,而是「怎么用它的 ctx.Request().Referer() 和响应控制来拦截非授权来源」。
Referer 校验中间件必须注意的三点
- 防盗链依赖的是 HTTP 请求头中的
Referer字段,但该字段可被客户端随意伪造或省略(比如 curl 不带 -H 就默认不发),所以它只适合做「粗粒度防护」,不能替代鉴权 - 空
Referer(如直接在地址栏输入 URL、HTTPS 页面引用 HTTP 资源)会被浏览器策略清空,需明确是否允许——否则静态资源会 403 -
ctx.Request().Referer()返回的是字符串,不自动解析域名,需手动提取 host;用strings.Contains匹配子串有风险(比如evil-gitee.com会被gitee.com误放行)
示例中间件逻辑:
func AntiHotlink(allowedHosts []string) fiber.Handler {
return func(c *fiber.Ctx) error {
referer := c.Get("Referer")
if referer == "" {
return c.Status(fiber.StatusForbidden).SendString("Referer required")
}
u, err := url.Parse(referer)
if err != nil || u.Host == "" {
return c.Status(fiber.StatusForbidden).SendString("Invalid Referer")
}
for _, host := range allowedHosts {
if u.Host == host || strings.HasSuffix(u.Host, "."+host) {
return c.Next()
}
}
return c.Status(fiber.StatusForbidden).SendString("Hotlinking not allowed")
}
}
然后挂载到静态路由:
app.Static("/uploads", "./uploads")
app.Use("/uploads/*", AntiHotlink([]string{"myapp.com", "localhost:3000"}))
静态文件服务中 Content-Disposition 和重定向陷阱
- 单纯返回 403 会让前端图片显示为“裂图”,体验差;更常见的做法是返回一个默认占位图(如
/static/forbidden.png),但注意:不能用 302 重定向到该图,否则新请求仍会带原Referer,再次触发中间件,陷入循环 - 正确方式是直接
c.SendFile("./static/forbidden.png"),并确保该路径不在防盗链中间件覆盖范围内(比如把占位图放在/static,而中间件只作用于/uploads) - 如果要强制下载而非展示(比如 PDF),可在通过校验后设置:
c.Set("Content-Disposition", "attachment; filename=\"report.pdf\"")否则浏览器可能内联渲染,暴露原始 URL 给用户右键另存
使用 Nginx 做前置防护比纯 Fiber 更可靠
-
Fiber层校验发生在应用层,请求已进 Go 进程,CPU 和内存已消耗;高频盗链攻击下,不如在反向代理层就拦截 - Nginx 配置更高效:
location ^~ /uploads/ { valid_referers none blocked server_names *.myapp.com; if ($invalid_referer) { return 403; # 或:rewrite ^/uploads/(.*)$ /static/forbidden.png break; } } - 若你用
Fiber直连公网(无 Nginx),那中间件是唯一选择;但生产环境几乎都会套一层反代,此时Fiber中间件应作为兜底,而非主力
真正的难点不在代码怎么写,而在于:你得清楚哪些资源要保护、哪些 Referer 必须放行(比如管理后台 iframe 嵌入)、以及是否接受空 Referer —— 这些决策一旦写死,后续改起来比加几行中间件麻烦得多。











