revel框架无内置referer校验,需手动编写中间件:解析url、小写归一化host、白名单map比对,并显式处理空referer;静态资源须精确路径绑定拦截器;nginx层valid_referers为必要补充;高价值资源推荐hmac签名临时链接。

Revel框架里Referer校验必须手动写中间件
Revel 没有内置防盗链机制,Interceptor 或 Filter 都不会自动读取或校验 Referer 头。你得自己解析请求头、提取 host、比对白名单——漏掉任意一步都可能被绕过。
常见错误是直接用 strings.Contains(r.Header.Get("Referer"), "mydomain.com"),结果 evilmydomain.com 也能通过。正确做法是用 net/url.Parse 解析 Referer,再严格比对 u.Host:
- 空 Referer(如用户直接在地址栏输入图片 URL)默认被拒绝,但需显式决定是否放行:
if referer == "" { if !allowEmptyReferer { c.Abort(403) } } - 域名比对前必须小写归一化:
strings.ToLower(u.Host),否则EXAMPLE.COM会被误判 - 白名单建议用
map[string]struct{}存储,避免每次遍历切片 - 不要在中间件里调用
c.RenderBinary或c.ServeFile,那是 controller 的职责
静态资源路径要显式绑定到Filter,否则不生效
Revel 默认把 /public 或 /static 下的文件走静态路由分支,而 Intercept 默认不覆盖该分支。如果你只想保护 /static/uploads/ 下的图片,不能只注册全局 Filter,必须精确匹配路径:
- 在
app/init.go中用revel.Intercept绑定到具体路径前缀:revel.Intercept(checkReferer, revel.BEFORE, &StaticUploadsController{}) - 或者更稳妥:把上传文件路由全部收口到一个 controller(如
DownloadController.Show),再对该 controller 应用拦截器 - 别依赖
revel.StaticDir自动服务——它绕过所有中间件逻辑
Nginx 层加一层 valid_referers 是必要补充
Revel 是应用层,Referer 可被客户端伪造。哪怕你的 Go 代码校验再严,攻击者 curl -H "Referer: https://yourdomain.com" 就能绕过。所以必须在 Nginx 做第一道过滤:
- 在
location ~* \.(jpg|png|pdf|zip)$块里配置:valid_referers none blocked *.yourdomain.com; -
none放行直接访问,blocked放行被代理清洗过的 Referer(比如某些企业防火墙会清空) - 注意
valid_referers不支持正则表达式匹配子域名以外的模式,*.yourdomain.com能匹配app.yourdomain.com,但不匹配yourdomain.com.cn - 若返回 403,Nginx 不会把请求转发给 Revel,性能和安全性都更高
Token 签名 URL 更适合高价值资源
纯 Referer 校验对下载包、视频片段这类高带宽资源风险太大。Revel 可以生成带签名的临时链接,比如 /download/file.zip?token=abc123&exp=1734392580:
- 签名算法推荐 HMAC-SHA256:
hmac.New(sha256.New, []byte(secretKey)),拼入文件路径 + 过期时间戳 - controller 中校验:
if time.Now().Unix() > exp || !hmac.Equal(expectedSig, actualSig) { c.Abort(403) } - 前端获取链接时必须走 API,不能暴露 secretKey;token 有效期建议控制在 5–30 分钟
- 这种方案天然防 Referer 伪造,也防链接长期泄露,但会增加一次后端计算开销
真正难的是混合策略的边界处理:比如允许搜索引擎爬虫(空 Referer)下载图片,但禁止镜像站(非白名单 Referer);又比如 CDN 回源时 Referer 可能被改写成 CDN 域名。这些细节不写死在配置里,光靠中间件逻辑很难全覆盖。











