Gin 默认不处理 Referer 防盗链,因其为可伪造字段,框架仅提供基础读取能力;需自行实现中间件校验白名单域名(支持通配符),并确保静态资源路由经过该中间件,但 Referer 校验不可替代服务端鉴权。

为什么 Gin 默认不处理 Referer 防盗链
Gin 本身不内置防盗链逻辑,因为 Referer 是 HTTP 请求头中的可伪造字段,框架层无法也不应替你做业务级的来源判定。它只提供 c.Request.Header.Get("Referer") 这样的基础读取能力,是否校验、如何校验、白名单怎么维护,全由你决定。
如何写一个轻量但可靠的防盗链中间件
核心是判断请求头中的 Referer 是否为空、是否来自允许的域名(支持子域名通配),并提前终止非法请求。注意几个关键点:
-
Referer可能为空(直接访问、HTTPS→HTTP 跳转、浏览器隐私模式); - 不能只用
strings.Contains简单匹配,否则example.com会误放行badexample.com; - 推荐用
url.Parse提取 host 后做精确比对或正则匹配; - 建议把白名单定义为
[]string,避免硬编码在中间件函数里。
示例代码片段:
func ReferrerCheck(allowedHosts []string) gin.HandlerFunc {
return func(c *gin.Context) {
referer := c.Request.Referer()
if referer == "" {
c.AbortWithStatusJSON(403, gin.H{"error": "forbidden: missing referer"})
return
}
u, err := url.Parse(referer)
if err != nil || u.Host == "" {
c.AbortWithStatusJSON(403, gin.H{"error": "forbidden: invalid referer"})
return
}
host := u.Host
allowed := false
for _, allowedHost := range allowedHosts {
if allowedHost == host || (strings.HasPrefix(allowedHost, "*.") && strings.HasSuffix(host, strings.TrimPrefix(allowedHost, "*."))) {
allowed = true
break
}
}
if !allowed {
c.AbortWithStatusJSON(403, gin.H{"error": "forbidden: referer not allowed"})
return
}
c.Next()
}
}
使用时:r.Use(ReferrerCheck([]string{"*.myapp.com", "localhost:3000"}))
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
静态资源路由必须放在防盗链中间件之后
如果你用 router.Static("/assets", "./public/assets") 提供图片、JS、CSS 等资源,而防盗链中间件注册在全局(router.Use()),那它会对所有请求生效——包括 /assets/logo.png。这是对的;但如果你把防盗链中间件只加在某个 Group 里,而静态资源路由没包含进去,那就完全绕过了校验。
常见错误配置:
router := gin.Default()
router.Static("/assets", "./public/assets") // ❌ 这里没走防盗链
api := router.Group("/api")
api.Use(ReferrerCheck(...)) // ✅ 只保护 /api 下的接口
正确做法是让静态路由也经过中间件,或者单独为静态路由加中间件:
router := gin.Default()
router.Use(ReferrerCheck([]string{"*.myapp.com"}))
router.Static("/assets", "./public/assets") // ✅ 现在受保护了
Referer 校验容易被绕过,别把它当安全边界
Referer 是客户端可随意修改的请求头,curl、Postman、甚至浏览器开发者工具都能轻易伪造。它只适合做“防止懒人盗链”的轻量防护,比如阻止别人直接在博客里 <img src="https://yoursite.com/assets/secret.jpg">。
真正敏感的资源(如用户私有附件、付费内容)必须配合服务端鉴权:JWT 校验、签名 URL、登录态 session 检查等。防盗链中间件只是第一道视觉过滤器,不是锁。

















