
核心要点(TL;DR)
- 只读挂载防篡改最彻底,但需配合发布流程改造,适合静态资源与模板目录。
- 文件监控负责发现,WAF 负责拦截,两者互补而非替代。
- Nginx 层禁用上传目录 PHP 执行,是成本最低的兜底措施。
- 防篡改核心是缩短发现时间与可回滚,而非追求零改动。
凌晨两点,首页被换成黑页,搜索引擎快照里还挂着赌博链接——这是运维最不想接到的电话。Nginx+PHP 站点被篡改,通常不是漏洞有多高级,而是文件被改了却没人第一时间知道。本文对比文件监控、WAF、只读挂载三种网页防篡改思路,给出可直接复制的命令与上线检查清单,帮你在当天完成第一层防护。
三种方案到底在防什么
先明确边界,避免买错药:
- 文件监控:解决“发现”。基于 inotify 或哈希基线,文件一变就告警,属于事后但最快的手段。
- WAF:解决“拦截”。在 HTTP 层挡住上传 Webshell、SQL 注入等入侵路径,属于事前。
- 只读挂载:解决“兜底”。把代码目录挂成只读,即使拿到 shell 也写不进去,属于事中阻断。
三者不是替代关系。只上 WAF,攻击者用 SSH 弱口令登进来照样改文件;只做只读,发布流程会立刻卡住。合理做法是分层组合。
方案一:文件监控,先建立基线再谈告警
没有基线的监控等于没有监控。先在发布完成后生成哈希清单:
find /var/www/html -type f \( -name '*.php' -o -name '*.html' -o -name '*.js' \) \
-not -path '*/cache/*' -print0 | xargs -0 sha256sum > /opt/baseline.sha256再部署实时监控脚本,只盯代码与模板目录:
inotifywait -m -r -e modify,create,delete,move \
--exclude '(cache|logs|uploads)' \
--format '%T %w%f %e' --timefmt '%F %T' \
/var/www/html >> /var/log/web_tamper.log注意两点:大站点需调大 fs.inotify.max_user_watches;日志要接入告警通道,否则文件只是安静地写进磁盘。发现变更后,用 sha256sum -c /opt/baseline.sha256 比对,非发布窗口内的不匹配项优先按入侵处理。
方案二:WAF,把上传目录的执行权限关掉
很多篡改源头是上传目录里的 PHP 被直接访问执行。Nginx 层一条配置就能堵住大部分:
location ~* ^/(uploads|images|attach)/.*\.(php|phtml|php5)$ {
deny all;
return 403;
}同时收紧可写范围,只允许必要目录被 PHP 写入:
location ~ \.php$ {
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}规则型 WAF(如 ModSecurity + OWASP CRS)能补拦截层,但要预留调优时间,误杀会直接打挂业务。若使用 AegisX 的防护能力,可把 Web 攻击拦截与文件完整性告警放在同一控制台,缩短从告警到处置的路径。
方案三:只读挂载,最彻底也最考验发布流程
把代码目录挂成只读,攻击者即使拿到 www-data 权限也无法落盘:
mount --bind /var/www/html /var/www/html
mount -o remount,ro,bind /var/www/html写入 /etc/fstab 固化:
/var/www/html /var/www/html none bind,ro 0 0代价是发布流程必须改造:卸载只读、同步、重新挂载。建议封装脚本,并只对静态资源、模板、代码目录只读,cache、logs、session 单独挂可写,否则 PHP 会因写日志失败报错。
三种方案对比与选型
| 维度 | 文件监控 | WAF | 只读挂载 |
|---|---|---|---|
| 作用阶段 | 事后发现 | 事前拦截 | 事中阻断 |
| 部署成本 | 低,几十行脚本 | 中,需规则调优 | 中,需改发布流程 |
| 性能开销 | 低到中 | 中 | 几乎为零 |
| 主要风险 | 告警疲劳 | 误杀业务 | 发布失败 |
选型建议:中小站点先做 Nginx 加固 + 文件监控;有合规要求或攻击面大的站点补 WAF;静态资源与模板目录优先只读。
上线检查清单
- 代码目录已生成 sha256 基线并纳入版本管理。
- inotify 监控覆盖代码与模板,已排除 cache/logs/uploads。
- 上传目录 PHP 执行已返回 403。
- 可写目录仅限 cache、logs、session、uploads。
- 只读挂载有对应发布脚本,回滚步骤已演练。
- 告警接入值班通道,明确 15 分钟内响应。
行动建议:今天先完成第 1、2、3 项,成本最低、收益最直接;本周内补齐只读挂载与发布脚本。网页防篡改的目标不是零改动,而是改动可控、异常可见、回滚可执行。
常见问题(FAQ)
网页防篡改只装 WAF 够不够?
不够。WAF 主要拦截外部入侵路径,如 SQL 注入、文件上传 Webshell,但无法阻止攻击者通过 SSH、弱口令或供应链进入后直接改文件。网页防篡改需要“入口拦截 + 文件变更发现 + 只读兜底”三层配合,WAF 只是第一层,缺少文件监控时篡改可能数天都无人发现。
只读挂载会不会影响网站正常更新?
会影响,但可控。只读挂载后发布流程必须改为“卸载只读—同步文件—重新挂载”,建议用脚本封装成一条发布命令,并在维护窗口执行。静态资源、模板、上传目录适合只读;需要频繁写入的缓存、日志、session 目录应单独挂载为可写,避免整站只读导致 PHP 报错。
inotify 监控大量文件会不会拖慢服务器?
取决于监控范围与事件频率。默认 inotify 上限为 8192 个 watch,大站点需调大 fs.inotify.max_user_watches。建议只监控代码与模板目录,排除 cache、logs、uploads,并用 inotifywait 的 --exclude 过滤;单机十万级文件以内开销通常可接受,更高量级应改用审计日志或集中式文件完整性工具。
怎么判断告警是正常发布还是被篡改?
靠基线哈希与发布记录比对。上线前对代码目录生成 sha256 清单并纳入版本管理,监控脚本发现变更后自动比对哈希与最近一次发布记录;不在发布窗口内、哈希不匹配、且文件属主异常(如 www-data 可写)的变更优先按入侵处理,先隔离样本再回滚。
中小站点预算有限,优先做哪一项?
优先做 Nginx 层加固加文件监控。禁用上传目录 PHP 执行、限制可写目录、关闭不必要的目录浏览,成本几乎为零;再用 inotifywait 脚本对代码目录做变更告警,几十行脚本即可上线。只读挂载与 WAF 可在业务稳定后逐步补齐,形成分层防护。