Apache可通过SetEnvIf匹配User-Agent设环境变量,再用Require not env(2.4+)或Deny from env(2.2)拒绝访问;正则应宽松匹配子串如"curl",注意大小写与配置语法升级,需配合Require all granted生效。

用 SetEnvIf 匹配 User-Agent 并拒绝访问
Apache 本身不直接支持基于 User-Agent 的 deny/allow 语句,但可以通过 SetEnvIf 预设环境变量,再配合 Require not env(2.4+)或 Deny from env(2.2)实现拦截。这是最轻量、无需模块额外加载的方案。
常见错误是把正则写成完整字符串匹配,比如写成 ^curl/.*$ 却忘了 User-Agent 实际可能是 curl/8.6.0 或带空格的 curl/8.6.0 libcurl/8.6.0 —— 正则应宽松,用 curl 或 python-requests 这类子串即可。
-
SetEnvIf User-Agent "curl" bad_bot—— 匹配任意位置含 "curl" -
SetEnvIf User-Agent "(python-requests|httpie|wget)" bad_bot—— 多个客户端用括号分组 - 注意大小写:默认不区分,如需严格匹配加
i标志:SetEnvIf User-Agent "(?i)sqlmap" bad_bot
Apache 2.4 中必须用 Require not env 替代旧版 Deny
升级到 2.4 后,Order/Deny/Allow 已废弃,继续用会报错 Invalid command 'Deny', perhaps misspelled or defined by a module not included in the server configuration。必须切换为基于 mod_authz_core 的新语法。
配置片段示例(放在 或 块内):
SetEnvIf User-Agent "(?i)sqlmap|nikto|dirbuster" bad_bot
<requireall>
Require all granted
Require not env bad_bot
</requireall>
关键点:
-
Require all granted是放行基础策略,否则全站 403 -
Require not env bad_bot才是实际拦截逻辑,顺序不能颠倒 - 若同时有 IP 白名单需求,可叠加
Require ip 192.168.1.0/24,但需确保RequireAll内所有条件都满足才放行
绕过检测的常见方式与应对建议
User-Agent 是客户端自定义字段,极容易伪造,所以这招只适合防御自动化扫描器或低门槛爬虫,不能当作安全边界。真实攻击者改个 UA 就绕过了。
如果你发现拦截失效,大概率是对方用了随机 UA 或模仿浏览器(如 Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36)。此时可补充行为特征判断:
- 检查请求头是否缺失
Accept、Accept-Language等浏览器标配字段 - 统计单 IP 短时间请求数,用
mod_evasive或mod_security做速率限制 - 对疑似流量返回验证码或 JS 挑战(需前端配合),纯 Apache 无法完成
单纯靠 UA 黑名单,维护成本高、误伤风险大,比如某些监控系统也会用 curl,一并封掉可能影响告警。
测试是否生效的最快方法
别等上线后看日志,本地用 curl 直接验证:
curl -I -A "sqlmap/1.7.2" https://yoursite.com/ curl -I -A "Mozilla/5.0" https://yoursite.com/
前者应返回 403 Forbidden,后者是 200 OK 或正常状态码。注意加 -I 只看响应头,避免下载正文干扰判断。
如果始终 200,检查三处:
- Apache 配置是否在生效的虚拟主机或目录块里(不是写在注释里或错误的
) - 是否漏了
Require all granted—— 缺它就全站 403 - 重启 Apache 了吗?
sudo systemctl reload apache2(Debian/Ubuntu)或sudo apachectl graceful(macOS)
UA 拦截逻辑简单,但生效链路长:请求进来 → 匹配 SetEnvIf → 设置环境变量 → Require 检查 → 返回结果。任一环断开都会静默失败,排查时得逐段确认。









