利用HTTP Referer实现图片防盗链:原理与NestJS实战

作者:星河时间:2026-10-31 05:58:57浏览:483

本文详解利用HTTP Referer头实现图片防盗链的原理,通过NestJS全局中间件拦截非白名单域名请求并返回403。深入解析Referer拼写历史、Referrer-Policy策略(如no-referrer)及其在Meta标签、HTML属性和HTTP头中的优先级,帮助开发者解决跨站图片加载导致的流量费用激增问题。

前言

上周突然发现个人站点的所有图片均返回403状态码,此前一直正常。由于发布文章时习惯先发布至掘金平台,随后直接复制内容至个人站点,从而省去了在个人站点单独上传图片的步骤,这种方式一直非常便捷。

前言

并未进行任何操作,图片却突然无法访问。推测可能是平台方采取了“开源节流、降本增效”的措施,即通过限制跨站图片引用以控制流量成本。当大量站点直接引用其图片导致流量费用大幅上升时,平台方通过设置防盗链机制,对非授权域名的访问统一返回403错误。

防盗原理

许多读者可能好奇,这类图片防盗机制具体是如何实现的?

我们可以模拟这一场景:配置服务器,使所有来自不受信任域名的图片资源请求均返回403状态码。

准备几个域名

即使没有真实域名也不必担心,可以直接在本地进行模拟。例如,这里使用SwitchHosts工具为本地环境添加了三个域名,并将它们全部指向本地IP地址。

前言

配置完成后,这三个域名均可以正常访问本地服务。

服务端逻辑

静态资源目录

此处沿用之前的nest服务进行演示,该服务此前已配置了静态资源目录路径。

app.useStaticAssets(join(__dirname, '../static'), {
  prefix: '/static',
}); // 静态资源

前端访问图片

<img class="my_img" src="http://nanjiu.com:3000/static/sy.jpg" />

当前使用nanjiu.com域名进行代理访问,图片可以正常加载显示。

前言

防盗中间件

我们可以实现一个全局中间件来处理图片访问请求。若访问域名不在预设的信任白名单内,则直接返回403状态码。

// 白名单
const whiteList = ['nanjiu.com', 'fenanjiu.com']
 // 图片防盗中间件
function imgMiddleware(req, res, next) {
  console.log('--req', req.headers)
  // 获取资源类型
  const type = req.headers.accept || ''
  if(!type.includes('image')) {
    // 不是图片资源,直接放行
    next()
    return
  }
  const referer = req.headers.referer || ''
  // 获取referer的域名
  const { hostname } = url.parse(referer, true)
  if(referer && whiteList.includes(hostname) || !referer) {
    // 访问域名在白名单内,放行 !referer表示直接访问图片(比如浏览器地址栏输入图片地址)
    res.status(200)
    next() 
  }else {
    // 访问域名不在白名单内,返回403
    res.status(403)
    res.send('逮到你了,又来偷我图片是吧!')
  }
}

需要注意的是,全局中间件的注册顺序必须位于useStaticAssets配置之前。

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  app.setGlobalPrefix('api'); // 全局路由前缀
  app.use(cors()); // 允许跨域
  app.use(json({ limit: '10mb' })); // 允许上传大文件
  app.use(urlencoded({ extended: true, limit: '10mb' })); // 允许上传大文件
  app.use(imgMiddleware) // 图片防盗中间件
  app.useStaticAssets(join(__dirname, '../static'), {
    prefix: '/static',
  }); // 静态资源
  await app.listen(3000);
  console.log(`Application is running on: ${await app.getUrl()}`);
}
bootstrap();

从上述代码可见,当前受信任的域名仅包含nanjiu.com和fenanjiu.com。

当使用sy.com域名访问nanjiu.com域名下的图片时,请求将触发防盗逻辑,返回403状态码。

前言

并返回提示信息:“逮到你了,又来偷我图片是吧!”

前言

Referer

从上述防盗原理的实现来看,核心关键在于referer。那么,referer具体指什么?为何它能用于图片防盗?

Referer是什么

MDN官方解释如下:

Referer 请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。服务端一般使用 Referer 请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。

由此可知图片防盗的基本原理:服务端通过解析请求头中的Referer来识别访问来源,进而判断是否返回图片资源。

Referer这个单词实际上是Referrer的错误拼写,这源于历史原因。在早期HTTP规范中即存在此拼写错误,为了保持向后兼容,最终将错就错沿用至今。

拼写错误仅出现在 Request Headers 的 Referer 中,而在其他领域如General Headers、 JavaScript 及DOM中,均使用正确的拼写形式。

Referrer-Policy

Referrer-Policy 首部用来监管哪些访问来源信息——会在 Referer 中发送——应该被包含在生成的请求当中。

该策略用于控制 Referer 头返回的具体内容。

它包含以下属性值:

  • no-referrer: 整个 Referer 首部会被移除。访问来源信息不随着请求一起发送。
  • no-referrer-when-downgrade(默认值): 在没有指定任何策略的情况下用户代理的默认行为。在同等安全级别的情况下,引用页面的地址会被发送 (HTTPS->HTTPS),但是在降级的情况下不会被发送 (HTTPS->HTTP)。
  • origin: 在任何情况下,仅发送文件的源作为引用地址。例如 https://example.com/page.html 会将 https://example.com/ 作为引用地址。
  • origin-when-cross-origin: 对于同源的请求,会发送完整的 URL 作为引用地址,但是对于非同源请求仅发送文件的源。
  • same-origin: 对于同源的请求会发送引用地址,但是对于非同源请求则不发送引用地址信息。
  • strict-origin: 在同等安全级别的情况下,发送文件的源作为引用地址 (HTTPS->HTTPS),但是在降级的情况下不会发送 (HTTPS->HTTP)。
  • strict-origin-when-cross-origin: 对于同源的请求,会发送完整的 URL 作为引用地址;在同等安全级别的情况下,发送文件的源作为引用地址 (HTTPS->HTTPS);在降级的情况下不发送此首部 (HTTPS->HTTP)。
  • unsafe-url: 无论是同源请求还是非同源请求,都发送完整的 URL(移除参数信息之后)作为引用地址。

面对这么多referrer策略,实际应用中该如何选择和使用?

meta标签使用

我们可以创建一个 name 为 referrer 的meta元素,从而为整个文档设置 referrer 策略。

<meta name="referrer" content="no-referrer">

我的个人站点正是采用此方法解决图片访问403问题的。但需注意,若为页面设置了no-referrer策略,会导致页面上所有请求均不发送referer,因此使用时需权衡利弊。

rel属性

可以在a、area、link标签上通过rel属性来单独指定referrer的策略。

<a href="xxx" rel="external nofollow"  rel="noreferrer">新地址</a>

referrerpolicy属性

可以在a、area、link、img、iframe、script标签上通过referrerpolicy属性来单独指定referrer策略。

<img class="my_img" referrerpolicy="no-referrer" src="http://nanjiu.com:3000/static/sy.jpg" />

例如,在上述例子中的图片加上referrerpolicy="no-referrer"属性后再进行访问,页面依然显示在sy.com域名下。

前言

观察请求头发现其中未携带referer,因此该请求成功避开了图片防盗逻辑。

Headers请求头

也可以直接修改 HTTP 头信息中的 Referer-Policy 值。例如使用 Nginx 时,可通过设置 add\_headers 指令来配置请求头。

add_header Referrer-Policy "no-referrer";

当 Headers 请求头与页面元素属性同时存在时,确定有效策略的优先顺序如下:

  • 元素级策略
  • 页面级策略
  • 浏览器默认

以上即为利用HTTP Referer实现图片防盗的详细图文示例,更多关于HTTP Referer图片防盗的资料请关注本站其它相关文章!

作者最新文章