在 Web 开发中,保护静态资源(如图片、文件等)不被滥用是一个常见需求,通过防盗链机制可以实现

  1. 成本控制:防止第三方站点盗用资源消耗带宽
  2. 安全防护:限制资源访问来源防止恶意爬取
  3. 数据准确 - 确保统计分析的访问来源可信度

本文将以图片资源为示例,介绍如何使用 Caddy 服务器实现灵活的防盗链机制

完整配置示例

oss.example.com {
    @deny_no_referer {
        header !Referer
        header Accept image/*
    }

    @deny_not_in_whitelist {
        header Referer *
        not header_regexp Referer ^https?://([^\s/:]+\.)*(example\.com|trusted\.site)(:\d+)?(/|$)
    }

    handle {
        respond @deny_no_referer "Access denied" 403
        respond @deny_not_in_whitelist "Access denied" 403
    }

    reverse_proxy 127.0.0.1:8080
}

配置解析与工作原理

Caddy 配置字段解析

Named matchers 命名匹配器

@name {
    ...
}

命名匹配器,可以定义一个命名以及一些指令,在需要这些指令的时候直接使用命名匹配器

Request Matchers 请求匹配器

header <field> [<value> ...]
  • header - 通过请求头字段 field ,以值 value 进行匹配
  • field - 请求头字段,例如 Referer
  • value - 匹配的值
header_regexp [<name>] <field> <regexp>
  • header_regexp - 通过请求头字段 field ,以正则的值 regexp 进行匹配
  • regexp - 正则表达式
not header <field> [<value> ...]
  • not - 取反匹配器的结果

核心匹配规则

基础防护层 - 阻断无 Referer 请求

@no_referer {
    header !Referer          # 缺失来源标识
    header Accept image/*    # 请求图片类资源
}

部分浏览器能支持在 web 加载图片资源时,不携带 Referer。如在 HTML 的 标签中增加如下代码

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

或者针对特定资源使用 referrerpolicy 属性

<!-- 图片不发送 Referer -->
<img src="image.jpg" referrerpolicy="no-referrer">

<!-- 链接不发送 Referer -->
<a href="https://example.com" referrerpolicy="no-referrer">Link</a>

<!-- 脚本加载不发送 Referer -->
<script src="script.js" referrerpolicy="no-referrer"></script>

白名单控制 - 只允许特定域名的引用

@deny_not_in_whitelist {
    header Referer *
    not header_regexp Referer ^https?://([^\s/:]+\.)*(example\.com|trusted\.site)(:\d+)?(/|$)
}

正则分解:

  • ^https?:// - 支持 HTTP/HTTPS
  • ([^\s/:]+\.)* - 匹配任意子域名
  • (example\.com|trusted\.site) - 主域名白名单,只允许 example.com 以及 trusted.site 访问
  • (:\d+)? - 允许带端口号
  • (/|$) - 路径开始或结束

测试验证方法

有正确的 Referer ,响应正确的图片

curl -H "Referer: https://www.example.com" https://static.example.com/image.jpg

用错误的 Referer ,响应 403 Access denied

curl -H "Referer: https://error.referer.com" https://static.example.com/image.jpg

没有 Referer ,请求头 Accept 字段从 image 开始,响应 403 Access denied (HTML no-referrer 的情况)

curl -H "Accept: image/jpg" https://static.example.com/image.jpg

没有 Referer ,请求头 Accept 字段不从 image 开始,响应正确的图片(直接下载图片或者链接单独在浏览器中打开图片)

curl https://static.example.com/image.jpg

参考文档

  1. Caddyfile
  2. 一种新的可应对空白 referer 的防盗链策略
Last modification:April 1, 2025
If you think my article is useful to you, please feel free to appreciate