恶意扫描不是随机试探,它是一套有步骤、有工具、有目标的攻击前奏。扫描者通常先用自动化工具批量探测目标站点的开放端口、Web组件版本、后台路径和已知漏洞指纹。很多中小网站并不是被“高手”攻破,而是在扫描阶段就暴露了太多信息,等于把门牌号和锁具型号贴在了外墙上。所以防护的第一原则是:不要让你的站点在扫描结果里显得“值得继续”。

识别扫描流量的典型特征

扫描流量和正常用户访问有明显区别。正常用户请求路径分散、频率有限、会加载页面关联资源;扫描器则表现为短时间内大量404请求、对不存在路径的枚举、对备份文件(如.zip、.sql、.bak)的探测、对特定漏洞路径(如/wp-admin、/phpmyadmin、/.env、/actuator)的集中访问。日志里如果出现同一IP在几秒内请求几十个不同URL,且User-Agent是脚本库默认值或缺失,基本可以判定为扫描。识别之后不要只封IP,因为扫描器常用代理池轮换,封IP效果有限,要结合行为策略处理。

关闭不必要的服务与端口

扫描的第一步通常是端口探测。很多服务器默认开放了不必要的服务,比如数据库端口3306对公网开放、Redis的6379未设密码、SSH的22端口允许密码登录。这些端口一旦被扫描到,后续攻击成本极低。防护上,数据库和缓存服务只监听内网地址,外部访问通过跳板或VPN(企业内部专用通道)完成;SSH改用密钥登录并限制来源IP;Web服务器只保留80和443,其他端口在防火墙层直接丢弃数据包而不是回复拒绝,这样扫描器无法判断端口是否真实存在。

隐藏Web组件指纹

扫描器识别漏洞的前提是知道目标运行什么软件和版本。Nginx、Apache、Tomcat、PHP、ThinkPHP、WordPress等组件都会在响应头或错误页面中暴露版本信息。例如默认的Server头会显示“nginx/1.18.0”,PHP的错误页面会显示“PHP 7.4.3”,ThinkPHP的报错页面直接标注框架名称。这些信息让扫描器可以直接匹配对应版本的已知漏洞。防护方法是修改响应头,关闭详细错误显示,自定义404和500页面,删除或修改默认的调试信息。对于Nginx,可以在配置中设置

server_tokens off;
;对于Apache,设置
ServerTokens Prod
和
ServerSignature Off
;PHP在php.ini中设置
expose_php = Off
。框架层面要关闭调试模式,生产环境不输出堆栈信息。

限制敏感路径的访问

扫描器最常做的事情就是枚举后台地址和敏感文件。很多网站后台路径是默认的/admin、/login、/manage,或者使用常见CMS的默认后台。扫描器拿到这些路径后,会进一步尝试弱口令或已知漏洞。防护上,后台路径不要使用常见名称,可以改成随机字符串或带二级目录的形式,同时后台登录页面增加IP白名单或二次验证。对于配置文件、备份文件、日志文件,直接在Web服务器层禁止访问,例如Nginx中:

location ~* \.(sql|zip|tar|gz|bak|log|env)$ { deny all; }

这样即使文件存在,扫描器请求也只会得到403,而不是下载文件内容。

部署Web应用防火墙(WAF)进行行为拦截

WAF不是简单的关键词过滤,它能够识别请求的语义和上下文。好的WAF规则可以拦截SQL注入探测、XSS测试、路径穿越尝试、恶意User-Agent、异常请求方法等。对于扫描行为,WAF可以设置频率阈值,比如同一IP在10秒内请求超过30个不同路径就触发验证码或临时封禁。开源的ModSecurity配合自定义规则可以做到基础防护,商业WAF则在规则更新和误报控制上更成熟。部署WAF后要定期查看拦截日志,分析扫描来源和探测目标,反向调整自己的防护策略。

利用蜜罐与陷阱路径反制扫描

被动防护之外,可以主动设置陷阱。在网站根目录放置一个隐藏链接,例如

<a href="/admin-console" style="display:none"></a>
,正常用户看不到,但扫描器会抓取并访问。当有IP访问这个路径时,直接将其加入黑名单。还可以在robots.txt中故意声明一个不存在的敏感目录,扫描器往往会优先读取robots.txt并跟进这些路径。访问这些蜜罐路径的IP基本可以确认是自动化工具,封禁误伤率极低。这个方法成本低、效果好,适合中小站点快速实施。

日志监控与实时告警

没有监控的防护是盲目的。扫描行为会在日志中留下大量痕迹,但如果不主动分析,这些痕迹就毫无价值。建议对Web访问日志和系统日志做集中收集,设置告警规则:单IP短时间大量404、请求路径包含常见漏洞关键词、请求方法为OPTIONS或TRACE、User-Agent为已知扫描器标识(如sqlmap、nmap、masscan、curl/7.54.0等)。可以使用Fail2ban这类工具自动读取日志并联动防火墙封禁,也可以将日志接入SIEM系统做更复杂的关联分析。实时告警的意义在于,当扫描发生时你能第一时间知道,而不是等被入侵后才去翻历史记录。

修补已知漏洞比拦截扫描更重要

扫描只是手段,漏洞才是目标。很多网站被攻破不是因为扫描无法拦截,而是因为扫描发现了真实存在的漏洞。比如使用了旧版本的Apache Struts2、Fastjson、Log4j2,或者后台存在弱口令,或者上传接口没有做文件类型校验。这些漏洞一旦被扫描器确认,攻击者会立即利用。所以防护的核心是持续修补漏洞:定期更新Web组件和框架,关注安全公告,使用漏洞扫描工具自查,对上传功能做严格校验,对输入参数做过滤和参数化查询。拦截扫描可以降低被发现的概率,但修补漏洞才能从根本上消除风险。

针对分布式扫描的应对策略

现在的扫描器很少用单IP长时间扫描,而是通过代理池、僵尸网络或云函数分散请求,每个IP只发少量请求,绕过频率限制。面对这种分布式扫描,单纯封IP几乎无效。应对方法是结合行为分析和全局统计:不只看单个IP的频率,而是看整个站点的异常请求比例。如果短时间内404请求占比突然升高,或者某个路径被大量不同IP同时访问,说明正在遭受分布式扫描。此时可以临时启用更严格的WAF策略,比如对所有请求增加JavaScript挑战,或者对可疑路径直接返回200但内容为空,让扫描器无法判断路径是否存在。对于使用云函数的扫描,可以分析请求头中的特征,如X-Forwarded-For、User-Agent中的云厂商标识,针对性处理。

使用HTTPS与安全头加固

HTTPS不仅加密传输,还能防止中间人篡改和流量劫持。扫描器对HTTPS站点的扫描成本更高,因为需要处理证书和加密协商。同时,配置安全响应头可以减少信息泄露和攻击面:

X-Content-Type-Options: nosniff
防止MIME类型嗅探;
X-Frame-Options: DENY
防止点击劫持;
Content-Security-Policy
限制资源加载来源;
Referrer-Policy
控制来源信息泄露。这些头部虽然不能直接阻止扫描,但能降低扫描器获取有效信息的效率,增加攻击难度。

建立应急响应流程

扫描发生后,除了封禁和加固,还要有清晰的应急流程。首先确认扫描是否成功发现了漏洞,检查相关路径是否存在异常访问记录;其次检查是否有文件被上传或修改,对比文件哈希和最近修改时间;然后检查是否有新增的管理员账号或异常登录;最后根据发现的问题决定是否需要下线修复或恢复备份。应急响应的核心是快速判断损失范围,而不是盲目重启服务。每次扫描事件后要做复盘,更新防护规则和修补清单,让下一次响应更快。

恶意扫描是网站安全的第一道防线,也是最容易被忽视的环节。很多攻击者在扫描阶段就会放弃那些“看起来很难搞”的目标,转而寻找更容易的猎物。你的站点不需要做到绝对安全,只需要比同类站点更难被扫描、更难被利用,就能避开大部分自动化攻击。把上述措施落实到位,扫描器在你的站点上能拿到的东西会越来越少,攻击者的兴趣也会随之降低。