针对海量图片资源的防盗链与防下载,需要构建多层防御体系。以下是经过实战验证的 Apache 深度防护策略:
一、基础层:Referer 防盗链(第一层过滤)
RewriteEngine On
# 定义允许的白名单域名(正则匹配,支持子域名)
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www.)?yourdomain.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?partner-site.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?cdn.yourdomain.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?localhost [NC]
# 对图片资源应用防盗链
RewriteRule .(jpg|jpeg|png|gif|webp|bmp|svg|ico)$ - [F,L]
说明:!^$ 允许空 Referer(部分客户端/邮件客户端),如需严格可移除。[F] 返回 403 Forbidden,[L] 终止后续规则。
二、核心层:Token 签名验证(防直链 + 防篡改)
1. 服务端 Token 生成逻辑(PHP/Python 示例)
2. Apache 配置(验证 Token + 过期时间)
RewriteEngine On
# 仅对图片目录启用
# 提取 URL 参数
RewriteCond %{QUERY_STRING} ^(?:.*&)?t=([^&]+)(?:&.*)?$ [NC]
RewriteRule .* - [E=TOKEN:%1]
RewriteCond %{QUERY_STRING} ^(?:.*&)?e=([^&]+)(?:&.*)?$ [NC]
RewriteRule .* - [E=EXPIRE:%1]
# 构建验证字符串:路径|过期时间
RewriteRule .* - [E=VERIFY_STRING:%{REQUEST_URI}|%{ENV:EXPIRE}]
# 计算期望的 HMAC(需要 mod_setenvif 或外部程序,这里用 Lua/外部脚本)
# 方案A:使用 mod_lua(推荐,高性能)
LuaHookAccessChecker /etc/apache2/scripts/verify_token.lua verify_token
# 方案B:使用外部程序验证(性能较低,适合低频)
# RewriteMap token_verify prg:/etc/apache2/scripts/verify_token.py
# RewriteCond ${token_verify:%{ENV:VERIFY_STRING}|%{ENV:TOKEN}} !^VALID$
# RewriteRule .* - [F,L]
# 检查过期时间
RewriteCond %{TIME} > %{ENV:EXPIRE}
RewriteRule .* - [F,L]
3. Lua 验证脚本(/etc/apache2/scripts/verify_token.lua)
-- 需要安装 libapache2-mod-lua
require "apache2"
require "hash"
require "string"
local secret = "YourStrongSecretKey_2024!"
function verify_token(r)
local token = r.subprocess_env["TOKEN"]
local expire = r.subprocess_env["EXPIRE"]
local path = r.uri
if not token or not expire then
return apache2.DECLINED -- 让 Rewrite 规则处理(返回403)
end
-- 检查是否过期
local now = os.time()
if tonumber(expire)
三、传输层:防直接下载 + 防右键保存
1. 禁用图片直接保存(Content-Disposition)
# 对图片强制 inline 显示,但阻止"另存为"对话框的默认行为
Header set Content-Disposition "inline"
# 禁止浏览器缓存图片到本地(减少离线查看)
Header set Cache-Control "private, no-store, max-age=0"
2. 添加水印(通过 mod_pagespeed 或后端处理)
# 使用 mod_pagespeed 自动添加水印(需安装)
ModPagespeedEnableFilters rewrite_images
ModPagespeedEnableFilters insert_image_dimensions
# 自定义水印滤镜
ModPagespeedImageMaxBytes 2097152
四、行为层:反爬虫与异常检测
1. 频率限制(mod_evasive 或 mod_security)
# 使用 mod_evasive 限制单 IP 图片请求频率
DOSHashTableSize 3097
DOSPageCount 5 # 同一页面5秒内超过5次
DOSSiteCount 50 # 同一站点5秒内超过50次
DOSPageInterval 5
DOSSiteInterval 5
DOSBlockingPeriod 600 # 封禁10分钟
DOSEmailNotify admin@yourdomain.com
DOSLogDir "/var/log/mod_evasive"
2. 使用 ModSecurity 高级防护
# 拦截无 Referer 的批量请求(爬虫特征)
SecRule REQUEST_FILENAME "@rx .(jpg|jpeg|png|gif|webp)$"
"id:1001,phase:1,block,log,msg:'Image access without referer',
chain"
SecRule REQUEST_HEADERS:Referer "@streq"
"setvar:ip.image_requests=+1,expirevar:ip.image_requests=60"
# 单 IP 60秒内超过100次图片请求则封禁
SecRule IP:IMAGE_REQUESTS "@gt 100"
"id:1002,phase:1,deny,status:403,msg:'Rate limit exceeded for images'"
# 拦截常见爬虫 User-Agent
SecRule REQUEST_HEADERS:User-Agent "@pm wget curl python scrapy"
"id:1003,phase:1,deny,status:403,msg:'Bot detected'"
五、应用层:前端 + 后端协同防护
1. 图片通过 Canvas 渲染(防右键保存)
fetch('/api/get-image-token?path=/uploads/photo.jpg')
.then(r => r.json())
.then(data => {
const img = new Image();
img.crossOrigin = 'anonymous';
img.onload = function() {
const canvas = document.getElementById('protected-img');
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// 添加视觉水印
ctx.font = '14px Arial';
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.fillText('© YourDomain ' + new Date().getFullYear(), 10, 30);
};
img.src = data.url; // 带 Token 的 URL
});
2. 动态缩略图 + 防盗链(防止原图泄露)
# 使用 mod_rewrite + mod_proxy 将缩略图请求代理到处理服务
RewriteRule ^/thumb/(d+)x(d+)/(.*)$
http://localhost:8080/thumbnail?w=$1&h=$2&path=$3 [P,L]
六、完整配置汇总
# ==================== 全局设置 ====================
ServerTokens Prod
ServerSignature Off
# ==================== 模块加载 ====================
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
LoadModule lua_module modules/mod_lua.so
# ==================== 图片目录防护 ====================
Options -Indexes -FollowSymLinks
AllowOverride None
Require all granted
RewriteEngine On
# ---- Layer 1: Referer 白名单 ----
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www.)?yourdomain.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?cdn.yourdomain.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www.)?localhost [NC]
RewriteRule .(jpg|jpeg|png|gif|webp|bmp|svg)$ - [F,L]
# ---- Layer 2: Token 验证 ----
RewriteCond %{QUERY_STRING} ^(?:.*&)?t=([^&]+)(?:&.*)?$ [NC]
RewriteRule .* - [E=TOKEN:%1]
RewriteCond %{QUERY_STRING} ^(?:.*&)?e=([^&]+)(?:&.*)?$ [NC]
RewriteRule .* - [E=EXPIRE:%1]
# 过期检查
RewriteCond %{TIME} > %{ENV:EXPIRE}
RewriteRule .* - [F,L]
# Lua HMAC 验证
LuaHookAccessChecker /etc/apache2/scripts/verify_token.lua verify_token
# ---- Layer 3: 响应头加固 ----
Header set Content-Disposition "inline"
Header set Cache-Control "private, max-age=300"
Header set X-Content-Type-Options "nosniff"
# 禁止图片被嵌入 iframe(点击劫持防护)
Header set X-Frame-Options "DENY"
# CSP 限制图片加载来源
Header set Content-Security-Policy "img-src 'self' data:; default-src 'none'"
# ---- Layer 4: 频率限制(需 mod_evasive)----
DOSPageCount 10
DOSSiteCount 100
DOSBlockingPeriod 300
# ==================== 日志记录 ====================
CustomLog "/var/log/apache2/image_access.log" "%h %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i" %{UNIQUE_ID}e"
防护效果总结
| 层级 | 防护手段 | 防御目标 |
|---|---|---|
| Layer 1 | Referer 白名单 | 阻止第三方网站直接引用 |
| Layer 2 | Token + HMAC + 过期时间 | 防止 URL 分享、直链访问 |
| Layer 3 | 响应头控制 + CSP | 防止右键保存、iframe 嵌入 |
| Layer 4 | 频率限制 + WAF | 阻止爬虫批量抓取 |
| Layer 5 | Canvas 渲染 + 动态水印 | 前端防保存、溯源追踪 |
这套方案的核心是 Token 签名机制——即使攻击者获取了图片 URL,Token 会在短时间内过期,且无法伪造签名,从根本上杜绝了盗链和批量下载。
到此这篇关于Apache配置实现对海量图片资源的深度防盗链与防下载策略的文章就介绍到这了,更多相关Apache海量图片防盗链与防下载内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!
