7.4.7 图片与静态资源防盗链

图片与静态资源防盗链#

防盗链的目标是限制非授权站点直接引用图片、CSS、JS 等静态资源,降低带宽消耗与盗链风险。本节给出基于 Referer 的防盗链与签名 URL 的完整示例,并包含安装检查、验证命令、排错与练习。

原理草图

文章图片

安装与准备(示例环境)
- 以 CentOS/RHEL 为例,安装并启用 Nginx:

sudo yum install -y nginx
sudo systemctl enable --now nginx
sudo nginx -v
  • 准备静态资源目录:
sudo mkdir -p /data/www/static/images
sudo cp /usr/share/nginx/html/nginx-logo.png /data/www/static/images/logo.png

基于 Referer 的防盗链(完整可用示例)
- 建议用 map 避免 if 副作用,并记录非法来源:

# /etc/nginx/conf.d/static.conf
map $invalid_referer $deny_by_referer {
    default 0;
    1       1;
}

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

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

    location ~* \.(jpg|jpeg|png|gif|css|js)$ {
        root /data/www/static;

        # 合法来源:允许空 Referer(兼容隐私模式)
        valid_referers none blocked server_names *.example.com cdn.example.net;

        # 非法来源返回 403
        if ($deny_by_referer) {
            return 403;
        }

        expires 7d;
        add_header Cache-Control "public, max-age=604800";
    }
}
  • 重新加载并验证:
sudo nginx -t
sudo systemctl reload nginx

命令与参数说明
- valid_referers none blocked server_names *.example.com
- none:允许无 Referer
- blocked:Referer 被隐藏但存在
- server_names:允许当前 server_name
- *.example.com:允许指定域名及子域
- map $invalid_referer $deny_by_referer
将变量 $invalid_referer 映射为自定义开关,便于统一处理。

签名 URL(secure_link 示例)
适用于高价值资源,避免 Referer 伪造:

# /etc/nginx/conf.d/secure.conf
server {
    listen 80;
    server_name download.example.com;

    location /protected/ {
        root /data/www;

        # URL 结构: /protected/file.jpg?md5=xxx&expires=时间戳
        secure_link $arg_md5,$arg_expires;
        secure_link_md5 "secret_key$uri$arg_expires";

        if ($secure_link = "") { return 403; }
        if ($secure_link = "0") { return 410; } # 已过期
    }
}
  • 生成 URL(示例脚本):
# 计算签名:md5(secret_key + uri + expires)
uri="/protected/images/logo.png"
expires=$(($(date +%s) + 600))
md5=$(printf "secret_key%s%d" "$uri" "$expires" | md5sum | awk '{print $1}')
echo "http://download.example.com$uri?md5=$md5&expires=$expires"

验证与测试命令
- 模拟合法 Referer:

curl -I -e "https://www.example.com" http://static.example.com/images/logo.png
  • 模拟非法 Referer:
curl -I -e "https://evil.com" http://static.example.com/images/logo.png
  • 模拟空 Referer(应放行):
curl -I http://static.example.com/images/logo.png
  • 查看日志定位来源:
tail -f /var/log/nginx/static_access.log

故障排查
- 现象:自站点资源 403
- 检查 valid_referers 是否包含 server_names 或主域名
- 检查 location 匹配是否命中静态资源
- 现象:CDN 回源 403
- 确认 CDN 回源 Referer,与源站白名单一致
- 必要时允许 CDN 回源域名
- 现象:移动端 WebView 误伤
- 放行 none 或添加网关域名为合法来源

练习
1. 将 none 去掉,观察隐私模式或空 Referer 的访问结果,并记录日志差异。
2. 给 images/ 目录返回占位图而不是 403,使用 try_files 完成。
3. 编写脚本批量生成 10 分钟有效期的签名 URL,并验证过期返回 410。