7.5.6 防盗链与访问控制

防盗链与访问控制是保护静态资源、限制访问来源和降低盗用带宽成本的关键手段。本节以 Nginx 为核心,介绍常见的防盗链策略与访问控制模型,提供可执行示例、排错方法与练习。

防盗链原理与场景#

  • 原理:通过校验请求头中的 Referer 或 URL 签名参数,判断请求是否来自允许的站点或客户端。
  • 常见场景:图片/视频/下载包、静态文件 CDN 回源、热链带宽盗用。
  • 限制Referer 可被伪造或缺失,需配合签名、Token、IP 白名单等增强。

原理草图(请求链路与校验点):

文章图片

基于 Referer 的防盗链#

使用 valid_referers 判断来源,并对非法请求进行拒绝或重定向。

配置示例(完整可运行片段)
文件路径:/etc/nginx/conf.d/static.conf

server {
    listen 80;
    server_name static.example.com;

    # 静态资源目录
    root /data/static;

    location ~* \.(jpg|jpeg|png|gif|webp|mp4|zip|tar\.gz)$ {
        # 允许空 Referer、被代理屏蔽的 Referer、以及指定域名
        valid_referers none blocked server_names
                       *.example.com example.com;

        # 变量说明:
        # $invalid_referer=1 表示不合法
        if ($invalid_referer) {
            return 403;
        }

        access_log /var/log/nginx/static_access.log;
    }
}

测试命令与预期效果

# 1) 合法来源(应返回 200)
curl -I -e "https://www.example.com/page.html" http://static.example.com/img/a.jpg

# 2) 非法来源(应返回 403)
curl -I -e "https://evil.com" http://static.example.com/img/a.jpg

# 3) 无 Referer(none 被允许,返回 200)
curl -I http://static.example.com/img/a.jpg

命令解释
- curl -I:只获取响应头,便于快速验证状态码。
- -e:设置请求头 Referer,模拟来源页面。
- valid_referers:定义合法来源,none/blocked/server_names 为常用内置类型。

基于签名/Token 的防盗链#

通过 URL 加签,避免 Referer 伪造。常见方案:secure_link

配置示例

server {
    listen 80;
    server_name download.example.com;
    root /data/download;

    # 需要模块:ngx_http_secure_link_module(官方内置)
    location /files/ {
        # URL 形式: /files/package.tar.gz?md5=签名&expires=时间戳
        secure_link $arg_md5,$arg_expires;
        secure_link_md5 "$secure_link_expires$uri secret_key";

        if ($secure_link = "") { return 403; }  # 缺少参数
        if ($secure_link = "0") { return 410; } # 过期

        try_files $uri =404;
    }
}

生成签名示例(本地)

# 变量说明
# expires: 过期时间戳(秒)
# uri: 资源路径
# secret: 与 Nginx 配置一致
expires=$(($(date +%s)+600))
uri="/files/package.tar.gz"
secret="secret_key"

# 生成 md5(base64 再替换字符,避免 URL 非法字符)
md5=$(printf "%s%s%s" "$expires" "$uri" "$secret" | \
  openssl md5 -binary | openssl base64 | tr +/ -_ | tr -d =)

echo "URL: http://download.example.com${uri}?md5=${md5}&expires=${expires}"

测试

# 1) 使用正确签名(应返回 200)
curl -I "http://download.example.com/files/package.tar.gz?md5=xxx&expires=yyy"

# 2) 过期签名(应返回 410)
curl -I "http://download.example.com/files/package.tar.gz?md5=xxx&expires=1"

访问控制:IP 白名单/黑名单与路径限制#

适用于接口、管理后台或敏感下载路径。

配置示例

server {
    listen 80;
    server_name admin.example.com;

    location /admin/ {
        allow 10.0.0.0/8;
        allow 192.168.0.0/16;
        deny all;

        # 基本认证(可选)
        auth_basic "Restricted";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}

生成认证文件

# 安装工具(以 Debian/Ubuntu 为例)
sudo apt-get install -y apache2-utils

# 创建用户
sudo htpasswd -c /etc/nginx/.htpasswd admin

命令解释
- allow/deny:基于源 IP 控制访问。
- auth_basic:基于 HTTP Basic Auth,适合后台保护。

常见排错与运维要点#

  • 排错 1:合法来源被拒绝
  • 检查 valid_referers 是否包含实际域名或子域名。
  • curl -I -e 模拟真实 Referer。
  • 排错 2:签名校验失败
  • 确认签名生成顺序与 Nginx 配置一致(expires + uri + secret)。
  • 时间戳是否已过期,服务器时间是否同步(NTP)。
  • 排错 3:缓存与 CDN
  • CDN 可能不传 Referer,需要在 CDN 配置透传或使用签名策略。
  • 日志定位
# 实时查看防盗链命中
tail -f /var/log/nginx/static_access.log

# 过滤 403/410
awk '$9 ~ /403|410/' /var/log/nginx/static_access.log | tail -n 20

练习#

  1. 为图片资源开启 Referer 防盗链,要求 example.com*.example.com 允许,非法返回 403。
  2. 使用 secure_link/files/ 路径配置签名,生成 10 分钟有效的下载链接并验证过期行为。
  3. /admin/ 增加 IP 白名单与 Basic Auth,验证未授权返回 401。