
核心要点(TL;DR)
- inotifywait 监听站点目录事件,配合 rsync 从可信源回滚,可把篡改恢复时间压到秒级。
- 监控要排除缓存、日志、上传目录,否则误报会淹没真实告警。
- 恢复必须从只读备份源拉取,禁止在受害机上原地备份,避免污染。
- 用 systemd 托管监控脚本并加日志轮转,才能长期稳定运行。
网站被挂马、首页被替换,最怕的不是被改,而是几个小时甚至几天后才发现。搜索引擎收录异常、用户投诉、品牌受损,往往都发生在你还没察觉的窗口期。本文给出一套可直接落地的网页防篡改方案:用 inotifywait 监听站点目录,发现变更立即告警,并用 rsync 从可信备份源自动回滚,把恢复时间从小时级压到秒级。
一、方案原理:监听、判断、恢复三步走
inotify 是 Linux 内核提供的文件系统事件通知机制,inotifywait 是其命令行工具。它能在文件被写入、移动、删除的瞬间触发回调,无需轮询扫描,开销低、延迟小。配合 rsync 的增量同步能力,就形成闭环:
- 监听:inotifywait 递归监控站点根目录,捕获 modify、create、move、delete 事件。
- 判断:过滤白名单目录与临时文件,命中可疑变更则记录并告警。
- 恢复:调用 rsync 从只读备份源拉取对应文件,覆盖被篡改内容,并保留现场副本。
关键前提:备份源必须是独立、只读、可信的,不能放在被监控的同一台机器同一目录,否则攻击者改一处,备份一起被污染。
二、环境准备与依赖安装
以 CentOS/RHEL 与 Debian/Ubuntu 为例,安装监控与同步工具:
# CentOS / RHEL
yum install -y inotify-tools rsync
# Debian / Ubuntu
apt update && apt install -y inotify-tools rsync
确认内核参数足够,避免大目录监控报错:
cat /proc/sys/fs/inotify/max_user_watches
# 建议调大
sysctl -w fs.inotify.max_user_watches=524288
echo 'fs.inotify.max_user_watches=524288' >> /etc/sysctl.conf
规划目录:站点目录 /var/www/html,可信备份源 /data/www_baseline(建议挂载为只读),隔离区 /data/quarantine 用于留存被改文件。
三、编写监控与自动恢复脚本
核心脚本 /usr/local/bin/web_guard.sh,逻辑是逐行读取 inotifywait 输出,命中规则后告警并回滚:
#!/bin/bash
SITE=/var/www/html
BASE=/data/www_baseline
QUAR=/data/quarantine
WEBHOOK="https://your-webhook-url"
inotifywait -m -r -e modify,create,move,delete \
--exclude '(uploads/|cache/|runtime/|logs/|\.log$|\.tmp$)' \
"$SITE" | while read -r dir event file; do
path="${dir}${file}"
rel="${path#$SITE/}"
ts=$(date '+%F %T')
echo "[$ts] $event $path" >> /var/log/web_guard.log
# 留存现场
mkdir -p "$QUAR/$(dirname "$rel")"
[ -f "$path" ] && cp -a "$path" "$QUAR/$rel.$(date +%s)"
# 从可信源恢复
if [ -e "$BASE/$rel" ]; then
rsync -a --checksum "$BASE/$rel" "$path"
action="已回滚"
else
rm -f "$path"
action="已删除新增文件"
fi
curl -s -X POST "$WEBHOOK" -H 'Content-Type: application/json' \
-d "{\"text\":\"[网页防篡改] $(hostname) $event $rel $action\"}" >/dev/null
done
要点说明:
--exclude用正则排除上传、缓存、日志目录,这是控制误报的关键。- 恢复前先
cp到隔离区,保留取证样本,便于事后分析入侵路径。 - 备份源不存在该文件时,说明是攻击者新增(如 webshell),直接删除而非保留。
四、用 systemd 托管并验证效果
写服务单元 /etc/systemd/system/web_guard.service:
[Unit]
Description=Web Tamper Guard
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/web_guard.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
启用并验证:
chmod +x /usr/local/bin/web_guard.sh
systemctl daemon-reload
systemctl enable --now web_guard
systemctl status web_guard
# 模拟篡改
echo 'hacked' >> /var/www/html/index.html
tail -f /var/log/web_guard.log
正常表现是:日志出现 modify 事件,文件被还原,告警消息送达。若没有反应,检查 inotifywait 是否递归生效、排除规则是否误伤。
五、误报控制与防护增强对比
纯监控容易陷入告警疲劳,需要按目录分级处理:
| 目录类型 | 典型路径 | 策略 |
|---|---|---|
| 代码与模板 | /var/www/html/*.php | 严格监控,变更即告警并回滚 |
| 上传目录 | /uploads | 排除监控,改为限制可执行权限 |
| 缓存与日志 | /cache /logs | 排除监控,仅做容量巡检 |
同时建议叠加:Web 目录对运行用户只读、定时用哈希清单做完整性比对、在边界部署 AegisX 的 WAF 能力拦截恶意上传与 webshell 访问,把「入口阻断」和「事后恢复」组合起来,单靠 inotify 只能发现不能预防。
六、上线检查清单
- 备份源独立存放且只读,权限与站点目录分离。
- 排除规则覆盖上传、缓存、日志、临时文件。
- 告警接入即时通讯群,消息含主机名、路径、事件、动作。
- 隔离区定期清理,保留至少 7 天取证样本。
- 日志配置 logrotate,防止磁盘写满导致监控中断。
- 每月做一次模拟篡改演练,确认恢复链路有效。
行动建议:先在测试站按上述脚本跑通「篡改—告警—回滚」全流程,再灰度到生产;发布流程与监控解耦,避免正常发版被误判。把网页防篡改做成常态机制,而不是出事后的临时救火。
常见问题(FAQ)
inotify 监控网站目录,服务器重启后脚本就没了怎么办?
用 systemd 托管即可。把监控脚本写成 service 单元,设置 Restart=always,执行 systemctl enable --now 开机自启。注意脚本内用绝对路径,并先确认 inotifywait 存在(yum/apt 安装 inotify-tools)。这样进程异常退出会被自动拉起,重启也不丢监控。
网站有用户上传和缓存目录,一改就告警,怎么减少误报?
在监控命令中用 --exclude 排除 uploads、cache、runtime、logs 等目录,或改用 --excludei 忽略大小写。更稳妥的做法是只监控代码与模板目录,把可变目录单独列出白名单。上线前先跑观察模式记录一天事件,再据此收敛规则,误报率会明显下降。
rsync 恢复会不会把正常更新也覆盖掉?
会,所以恢复必须区分场景。建议备份源保持只读,发布走独立流程;监控脚本只对白名单外的新增/修改文件触发恢复,并在恢复前把被改文件复制到隔离目录留证。对整站发布场景,可先暂停监控再发布,发布完成后重新启用。
只靠 inotify 告警够不够,还需要别的防护吗?
不够。inotify 属于事后发现,攻击者若拿到 root 可直接卸载或杀掉监控。建议叠加文件完整性校验(如定时比对哈希)、Web 目录只读挂载、最小权限运行 Web 服务,并在边界部署 WAF 拦截上传木马等入口行为,形成发现加阻断的组合。
告警发到哪里比较实用,邮件总是没人看?
优先发到即时通讯群机器人或短信,邮件只作归档。脚本里用 curl 调用 webhook 即可,消息中带上主机名、文件路径、事件类型和时间。关键目录变更设高优先级,普通变更合并成摘要每十分钟推送一次,避免告警疲劳。