Nginx 下载文件密码 / 验证码防护方案(针对爬虫拖垮服务器)
你需求分三类:
方案 A:HTTP 基础认证 auth_basic(最简单,浏览器弹窗输入账号密码,开箱即用;缺点:爬虫带 Authorization 头就能绕过,适合临时内部使用,防不住专业爬虫)
方案 B:ngx_secure_link 签名临时链接(推荐!),Nginx 原生模块,生成带时效的一次性下载 URL,链接带签名 + 过期时间,链接过期直接失效,爬虫就算拿到 URL,一段时间后就不能继续批量下载,非常适合防爬虫刷文件
方案 C:auth_request 子请求验证(验证码 / 页面表单验证),访问下载地址前,先跳转到网站页面输入图形验证码,后端验证通过后 Nginx 才放行文件(就是你说的「连接验证码」,体验最好,但需要后端代码)
同时必须搭配限流,不然就算有密码,爬虫持续并发请求依然会打满带宽。
方案 A:auth_basic 账号密码认证(最简单,快速上手)
模块ngx_http_auth_basic_module,绝大多数 Nginx 默认自带,无需编译。
1、生成密码文件
# CentOS
yum install httpd-tools
# Ubuntu/Debian
apt install apache2-utils
# 创建密码文件,添加用户 download
htpasswd -c /etc/nginx/.htpasswd download
# 然后输入两次密码
不想装 htpasswd,也可以用 openssl 生成加密密码:
openssl passwd -apr1 你的密码,然后手动写入文件,格式用户名:加密串
2、Nginx 配置(只保护下载目录)
server {
listen 80;
server_name yourdomain.com;
# 下载目录,例如 /files/ 下面所有文件需要密码
location ^~ /files/ {
auth_basic "请输入下载密码";
auth_basic_user_file /etc/nginx/.htpasswd;
root /data;
}
# 网站其他页面不认证
location / {
root /data/html;
}
}
校验配置 nginx -t,重载 nginx -s reload
访问http://domain/files/xxx.zip浏览器弹出账号密码框。
⚠️ 缺点:爬虫可以直接在请求头带上Authorization,拿到密码后依然可以批量循环下载,只能挡小白爬虫,不能解决你现在被爬虫持续拖死服务器的问题。
方案 B:secure_link 时效签名链接【强烈推荐,原生 Nginx,防爬虫最优】
Nginx 自带ngx_http_secure_link_module,需要确认编译时带上(nginx -V | grep secure_link)。
原理:下载链接由后端用密钥 + 文件路径 + 过期时间算出 MD5 签名,Nginx 收到请求校验签名是否正确、是否过期,校验成功才返回文件;真实文件目录设置 internal,外部不能直接访问原始文件名。
爬虫就算爬取到下载链接,链接短时间(比如 5 分钟)自动失效,无法批量遍历下载。
Nginx 配置示例
server {
listen 80;
server_name yourdomain.com;
# 密钥,后端代码生成链接时必须用同一个密钥,自己设置长随机字符串
set $secure_secret "MySecretKey2026";
# 对外访问的下载url,形如 /dl/MD5哈希?expires=时间戳
location ^~ /dl/ {
secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_secret$uri$arg_expires";
# 校验失败、过期返回403
if ($secure_link = "") {
return 403;
}
# 校验成功,重写到内部文件地址
rewrite ^/dl/(.*)$ /internal_files/$1 break;
}
# internal:外部不能直接访问这个路径,只能内部rewrite过来
location ^~ /internal_files/ {
internal;
root /data;
}
}
后端生成下载链接逻辑(伪代码)
- 文件真实路径:
/internal_files/test.zip
- 设置过期时间戳:当前时间 + 300 秒(5 分钟)
- 拼接字符串:
MySecretKey2026/dl/test.zip1728000000 - MD5 计算,urlencode
- 对外链接:
https://domain.com/dl/test.zip?md5=xxx&expires=时间戳
优势:
✅ 链接限时,泄露也不怕
✅ 爬虫不能猜文件名批量遍历
✅ 完全在 Nginx 层校验,不占用后端压力
方案 C:auth_request 子请求做图形验证码(你说的验证码页面)
适合场景:用户访问下载地址 → 跳转网页输入验证码 → 后端校验验证码,写入 session → Nginx 请求后端接口校验 session 有效,才返回文件。
需要后端程序(PHP/Java/Python 等)写验证码接口。
location ^~ /files/ {
auth_request /auth/check; # Nginx自动请求后端验证接口
root /data;
}
location /auth/check {
proxy_pass http://127.0.0.1:8080/api/verify; #你的后端验证码校验接口
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
逻辑:
- 用户访问
/files/xxx.zip
- Nginx 转发请求到
/auth/check - 后端判断:未验证验证码 → 返回 302 跳转到验证码页面;验证码验证成功返回 200
- Nginx 收到 200,放行文件;收到 401/403 拒绝下载
优点:图形验证码对爬虫拦截最强;缺点:需要开发后端接口。
✅ 必加配套:限流(解决爬虫打满服务器)
不管上面哪种认证,一定要加限流,限制单 IP 并发、请求频率,否则爬虫拿到有效链接依然会把带宽 / IO 打满,这是你当前问题的关键。
# 放在http{}全局段
limit_req_zone $binary_remote_addr zone=dl_limit:10m rate=5r/m; # 单IP每分钟最多5次下载请求
limit_conn_zone $binary_remote_addr zone=dl_conn:10m;
# 在下载location内部添加
limit_req zone=dl_limit burst=3 nodelay;
limit_conn dl_conn 2; # 单IP最多2个并发下载连接
- rate=5r/m:单 IP 每分钟最多 5 次下载请求,可以按需调整
- limit_conn:限制同时下载的并发数量,防止多线程爬虫
额外辅助防护(一起加上)
- 防盗链
valid_referers,只允许本站页面发起下载请求(referer 可以伪造,辅助)
- 日志分析,抓取高频 IP,自动拉黑(fail2ban)
- 识别爬虫 UA,直接返回 403
方案选型建议
- 内部使用,简单密码:方案 A auth_basic
- 对外网站,防止爬虫批量刷文件,推荐方案 B secure_link 时效签名链接,改动最小,性能好,防爬虫效果最强
- 需要图形验证码、人机验证:方案 C auth_request + 后端验证码 + session
该文章在 2026/10/8 9:53:36 编辑过