博主头像
LT技术站

行动起来,活在当下

  • 累计撰写 255 篇文章
  • 累计创建 131 个标签
  • 累计收到 0 条评论

目录

Web安全

防盗链到底防什么:Referer、签名 URL 与 CDN 鉴权

本文探讨网站防盗链的多层技术方案及误区:基础防盗链通过HTTP Referer头验证引用来源,但存在伪造风险(如curl工具可强制设置Referer),且仅能拦截网页嵌入盗链,无法防止本地下载。针对高价值资源,需结合签名URL(HMAC+过期时间校验)、业务端登录鉴权(验证用户权限与资源归属)、CDN Token鉴权等。视频防护需多层叠加:HLS分片鉴权、短时效签名、DRM加密、用户水印及流量监控。常见误区包括混淆防盗链与防下载本质(单纯限制URL无法阻断复制)、认为复杂路径可替代签名验证,以及过度缩短签名时效导致体验下降。建议按资源价值分层防护:普通图片用Referer白名单+拒空Referer,登录附件需鉴权+E签URL,软件包需E签+频率限制,会员视频强制Token鉴权+分片加密,高价值资料需叠加DRM和实时防抄袭监测。

浏览器 Web 安全基础系列

  1. 浏览器怎么判断是不是同一个网站

  2. Cookie 为什么会自动携带

  3. Session 登录状态为什么可能被劫持

  4. HTTPS 为什么仍然不够

  5. CORS 到底在限制什么

  6. CSRF 是怎么冒用登录状态的

  7. CSRF 如何防御

  8. XSS 为什么能在你的网站执行

  9. CSP 与浏览器安全响应头

  10. Clickjacking 点击劫持

  11. 第三方资源为什么危险

  12. 防盗链到底防什么(当前篇)

盗链指其他网站直接引用你的图片、视频或下载地址,内容显示在对方页面,带宽却由你的服务器或 CDN 承担。最基础的防盗链检查 Referer;私有资源则需要真正的权限校验或短期签名 URL。

Referer 防盗链流程

Referer 防盗链

其他网站引用:

<img src="https://cdn.example.com/images/photo.webp">

浏览器向你的 CDN 请求时可能发送:

Referer: https://other.example/article

服务器允许自己站点,拒绝其他来源:

const allowedHosts = new Set(['www.example.com', 'blog.example.com']);

function allowedReferer(req) {
  const referer = req.headers.referer;
  if (!referer) return false;

  try {
    return allowedHosts.has(new URL(referer).hostname);
  } catch {
    return false;
  }
}

Nginx 示例:

location ~* \.(jpg|jpeg|png|webp|gif)$ {
    valid_referers server_names *.example.com;
    if ($invalid_referer) {
        return 403;
    }
}

空 Referer 怎么处理

用户直接在地址栏打开资源、隐私策略、浏览器插件或协议降级都可能导致 Referer 缺失。

  • 允许空 Referer:兼容性更好,但更容易绕过;

  • 拒绝空 Referer:更严格,但可能误伤下载、客户端和分享场景。

普通博客图片通常可以允许空 Referer并拒绝明确的外站来源;高价值资源不要只靠 Referer。

Referer 可以伪造

浏览器页面脚本不能随便设置 Referer,但 curl、下载器和攻击者服务器可以:

curl -H "Referer: https://www.example.com/"   https://cdn.example.com/images/photo.webp

所以 Referer 防盗链主要防“网页直接引用”,不是强身份认证,也防不了有意下载。

签名 URL

私有文件可以生成带过期时间和 HMAC 的地址:

/download/report.pdf?expires=1783900000&signature=...

服务端签名:

import crypto from 'node:crypto';

function sign(path, expires, secret) {
  return crypto
    .createHmac('sha256', secret)
    .update(`${path}:${expires}`)
    .digest('base64url');
}

验证时检查过期时间和签名:

function verify(path, expires, supplied, secret) {
  if (Date.now() >= Number(expires) * 1000) return false;

  const expected = sign(path, expires, secret);
  const a = Buffer.from(expected);
  const b = Buffer.from(String(supplied || ''));

  return a.length === b.length && crypto.timingSafeEqual(a, b);
}
签名 URL 流程

签名必须覆盖资源路径和过期时间,否则攻击者可能把有效签名换到另一个文件上。还可以绑定用户 ID、资源 ID、清晰度或下载次数,但绑定 IP 容易误伤移动网络和代理用户。

登录鉴权与签名 URL 的关系

业务服务先检查用户是否有权访问文件,再签发短期 URL:

用户请求下载
→ 业务服务验证登录和资源权限
→ 生成 5 分钟签名 URL
→ CDN/资源服务验证签名
→ 返回文件

签名 URL 不是权限判断本身。服务端不能只要用户知道 fileId 就签发地址,仍要检查资源归属和角色权限。

为什么图片常用 URL 签名而不是 Authorization 头

<img>、<video> 和下载链接不方便统一添加自定义 Authorization 请求头。Cookie 或签名 URL 更适合浏览器原生资源标签。API 数据则更常使用 Cookie Session 或 Bearer Token。

视频保护

HLS 视频包含播放列表、分片、字幕和可能的密钥:

master.m3u8
segment-001.ts
segment-002.ts
key

只保护主 m3u8 不够,分片地址仍可能被下载。常见组合:

  • CDN Token 鉴权;

  • 短期签名 URL 或签名 Cookie;

  • 分片和密钥鉴权;

  • DRM;

  • 用户水印;

  • 并发、速率和异常下载检测。

任何能在终端播放的内容都无法保证绝对不可复制,目标是提高成本、限制规模和保留追踪能力。

防盗链与 CORS

CORS 控制 JavaScript 是否能读取跨源响应。<img> 即使没有 CORS 许可,也可能正常显示跨源图片。因此 CORS 不能替代防盗链。

Referer 防盗链决定是否返回资源;签名 URL 和登录鉴权决定请求是否获得授权。这三者层级不同。

选型建议

资源

推荐方案

普通博客图片

CDN Referer 白名单,按业务决定是否允许空 Referer

登录后附件

业务权限校验 + 短期签名 URL

软件安装包

短期签名 URL + 下载频率限制

会员视频

CDN Token、分片鉴权、短期 URL

高价值视频

DRM + CDN 鉴权 + 水印 + 风险检测

常见误区

防盗链等于防下载

不对。资源最终到达用户设备,只能增加滥用成本,不能保证不可复制。

URL 足够复杂就安全

隐藏地址不是授权。应使用不可伪造签名和服务端权限校验。

签名 URL 有效期越短越好

太短会导致弱网、断点续传和长视频播放失败,需要按资源大小和播放模式设计续签机制。

小结

Referer 防盗链适合减少普通网页盗用;签名 URL 适合限制链接构造和有效时间;登录鉴权负责判断用户是否有权限。高价值资源通常需要三层以上组合,而不是寻找“绝对防下载”的单一技术。

参考资料

那年今日11 月 12 日

    评论区