referer防盗链是通过校验http请求头中的referer字段是否来自预设白名单域名来防止资源盗用;gin中需自写中间件,用c.getheader("referer")获取并解析url提取host,与白名单精确匹配,空referer按策略处理,匹配失败返回403,且须注意cdn透传和referer可伪造的局限性。

什么是Referer防盗链,Gin里怎么判断
图片防盗链本质是校验HTTP请求头中的 Referer 字段是否来自白名单域名。Gin本身不内置防盗链逻辑,得自己写中间件拦截并判断。关键不是“有没有Referer”,而是“Referer是否合法”——空值、非HTTP协议、不在白名单里,都该拒绝。
- 空
Referer(比如直接地址栏访问、curl无-U)通常允许,但需明确配置; - 注意
Referer可被伪造,仅作基础防护,不能替代鉴权; - Gin中用
c.GetHeader("Referer")获取,别用c.Request.Referer()(它会 fallback 到 Referer 头,但语义模糊且易误判); - 匹配域名时建议用
strings.HasSuffix(referer, "example.com")或正则,避免子域名误放(如evil.example.com匹配example.com)。
如何写一个可配置的Gin防盗链中间件
把白名单、放行规则、响应行为都做成参数,避免硬编码。中间件返回 403 Forbidden 最合理,不要重定向或返回空白图——前者暴露路径,后者可能被缓存。
- 接收
[]string白名单,支持通配符如"*.example.com"(需自行解析,标准库不支持); - 对每个请求,提取
Referer的 host 部分(用url.Parse解析后取u.Host),再比对; - 静态资源路径要提前识别,比如只对
/static/和/upload/下的.png、.jpg生效,其他路由跳过; - 示例片段:
if strings.HasPrefix(c.Request.URL.Path, "/static/") && isImageExt(c.Request.URL.Path) { if !isValidReferer(c.GetHeader("Referer"), whitelist) { c.AbortWithStatus(http.StatusForbidden) return } }
常见踩坑:Referer为空、HTTPS混杂、CDN穿透
开发时本地测试常看到 Referer 为空,不是代码错了,而是浏览器策略或调试方式导致。生产环境更麻烦的是CDN——很多CDN默认不透传 Referer,或者改写成自己的域名。
- Chrome/Firefox在Referrer-Policy 为
no-referrer-when-downgrade时,HTTPS页跳HTTP图会清空Referer; - 如果用了Cloudflare、又开了“Hotlink Protection”,它会先拦一次,你的Gin中间件可能根本收不到原始
Referer; - 某些CDN(如腾讯云COS)需显式开启“回源携带Referer”,否则源站永远收不到;
- 测试时用
curl -H "Referer: https://test.com" http://localhost:8080/static/a.jpg比浏览器更可靠。
要不要加Referer白名单缓存或并发安全
白名单列表一般固定,没必要每次解析域名。但如果用正则匹配通配符,每次都要编译,就该提前 regexp.Compile 缓存。Gin中间件函数本身是并发安全的,但若你在中间件里改全局变量(比如动态更新白名单),必须加 sync.RWMutex。
- 白名单数组遍历开销极小,不用额外优化;
- 如果白名单超50个,建议转成
map[string]struct{}做 O(1) 查找; - 别在中间件里调用数据库或HTTP请求查白名单——延迟高、易拖垮整个服务;
- 调试时加
log.Printf("referer=%s, allowed=%t", referer, ok),但上线前删掉或用结构化日志控制级别。











