1. 网页被篡改的本质与常见攻击路径做运维这些年我见过太多网站被黑的现场首页被插了一行奇怪的外链、整站被换成赌博页面、后台被上传了一堆木马文件。这些事情发生之后很多人的第一反应是赶紧把文件改回来但如果不搞清楚攻击者是怎么进来的改完很快又会被人再次挂马陷入被篡改-修复-再被篡改的循环。先说一个基本认知网页被篡改本质上就是攻击者获得了你服务器上写文件的能力。无论他走的是漏洞利用、弱口令爆破、还是第三方组件后门最终都绕不开往你的网站目录里写入恶意文件这一步。所以防篡改的核心思路就两条第一尽量让攻击者拿不到写权限第二就算他拿到了写权限也要让他写不进去或者写了之后立刻被你发现并恢复。针对标题里的场景我主要讲Linux服务器上常见的防护思路和落地手段。这套东西不区分你用的是Apache、Nginx还是别的Web服务也不区分PHP、Python、Java还是前端静态页原理是通用的。在动手之前建议你先想清楚一个问题你要防的是被改之后能恢复还是压根改不了这两个目标对应的技术方案完全不同成本也不一样。我个人的建议是重要系统两者都要预算和运维能力有限的话优先保能及时发现、快速恢复这比单纯追求改不了更实际。2. 基础加固先把最容易进的门堵上2.1 文件权限与属主设置很多人建站的时候图省事直接把整个网站目录chmod -R 777或者把属主设成www:www之后又给了写权限这在攻击者眼里基本等于门户大开。正确的思路是能读就不写能执行就不读写把写权限压缩到最小范围。具体来说我建议这样设置路径推荐权限说明网站根目录755 或 750目录需要有读和执行权限但不需要写权限静态文件html/css/js/图片644只读即可PHP文件644只读即可Web服务以独立用户运行上传目录755属主设为Web运行用户只给必要的写权限且禁止解析脚本配置文件含数据库密码600 甚至 400权限越小越好只允许特定用户读取日志目录755通过日志轮转避免膨胀这里容易踩的坑是很多人把网站目录属主直接设成www用户然后又给www用户整个目录的写权限攻击者一旦通过Web漏洞拿到www用户的权限就可以随意修改任何文件。更稳的做法是把网站目录属主设为root:www目录权限 750只有个别需要动态写入的子目录比如上传目录、缓存目录才单独设置属主为www权限 700。另外启用SELinux或AppArmor的环境要注意文件权限只是第一层强制访问控制MAC会在权限之外再做一层拦截。生产环境里SELinux默认是Enforcing很多人嫌麻烦直接setenforce 0结果把这道防线也关了。如果你用的是CentOS/RHEL系列建议不要关闭SELinux而是针对你的Web服务单独配置布尔值或自定义策略。排查问题的时候可以先getenforce看一眼很多权限明明对了但还是访问不了的诡异问题最后都发现是SELinux在拦。2.2 Web服务与PHP运行用户隔离另一个高频问题是Web服务运行用户权限过大。如果你直接用root启动Nginx或Apache那攻击者一旦突破Web服务就相当于直接拿到了root权限后面什么防护都是摆设。正确做法是创建一个专门的低权限用户来运行Web服务比如useradd -r -s /sbin/nologin www用www用户启动PHP-FPM、Nginx的worker进程配合上面的文件权限设置即使被入侵攻击者拿到的也只是www用户的权限能写的目录非常有限。PHP环境里还有几个关键配置值得注意open_basedir限制PHP脚本能访问的目录范围即使脚本被攻破也无法读取目录之外的文件。disable_functions禁用高危函数比如exec、system、passthru、shell_exec、proc_open、popen等。不少一句话木马就是靠这些函数执行系统命令的禁掉能挡掉一大片脚本木马。关闭错误信息显示生产环境把display_errors设为Off避免路径泄露和报错信息被利用。上传目录禁止解析PHP在Nginx/Apache配置里对上传目录单独设置不经过PHP解析。比如Nginx下location ~* /upload/.*\.(php|php5)$ { deny all; }这个操作非常关键。很多人只做了上传格式校验攻击者上传一个shell.php.jpg配合解析漏洞照样能执行。直接在Web层把上传目录里的PHP解析禁止掉是最省心的方案。2.3 SSH与远程管理入口加固网页被篡改的入侵途径里SSH弱口令爆破占了相当大的比例。虽然标题重点是防网页篡改但入口不堵住后面做再多都是白搭。这里有几条可以立刻执行的加固措施禁用root直接登录PermitRootLogin no日常管理用普通用户加sudo。修改SSH默认端口Port 22999能有效减少被扫描命中的概率注意要同步改防火墙规则。启用密钥登录禁用密码登录PasswordAuthentication no。配置Fail2ban自动封禁短时间内多次失败尝试的IP。我自己管理服务器有个习惯远程管理口只对可信IP或内网网段开放公网一律不暴露。如果条件不允许至少要开Fail2ban配合强密码。这类措施不直接防篡改但能大幅降低被攻破的概率属于少惹事的思路。3. 文件系统层面的主动防护让文件改不动3.1 chattrLinux的只读保险箱前面讲的是权限层面的防护权限是有局限的www用户不能写文件但如果攻击者已经拿到了root权限或者利用漏洞提权成功普通权限就拦不住了。这个时候需要上文件系统层面的防护。chattrchange attribute是Linux上非常经典的一个命令可以给文件或目录设置特殊属性。与防篡改最相关的两个属性是iimmutable不可变和aappend only只允许追加。chattr i /var/www/html/index.html chattr i /var/www/html # 对整个目录设置不可变设置i之后即使是root用户也无法对这个文件进行修改、删除、重命名除非先把i去掉。攻击者就算拿到了root权限想改你的主页文件也会被拒绝这个特性对防篡改非常有用。实际用的时候有几个细节我要提醒一下chattr i对目录生效后目录内的已有文件不受影响但无法在目录里新建文件和删除文件。如果目录里需要动态生成文件比如缓存目录千万不要对整个目录加i否则程序直接报错。需要更新被锁定的文件时先chattr -i去掉属性改完再加回来。建议写一个小脚本自动化这个过程避免手动操作遗漏。a属性适合日志文件只允许追加、不允许修改和删除这样即使被入侵攻击者也很难清理日志对溯源很有帮助。要注意chattr依赖文件系统支持常规的ext4、xfs都支持但某些网络文件系统NFS、某些云盘可能不支持或行为不一致生产环境先验证一下。有些发行版上普通用户即使有root权限在特定内核配置下也可能遇到Operation not permitted这与内核的fs.protected_regular等安全参数有关不影响正常使用。3.2 只读挂载与特定场景的强制只读如果你管理的是纯静态网站、或者网站目录基本不变化更彻底的做法是把目录所在的分区以只读方式挂载。在/etc/fstab里加ro选项重启后整个分区就无法写入这种防护比chattr更底层、更难绕过。不过只读挂载的局限性也很明显大部分动态网站都需要写入session、缓存、上传文件整盘只读不现实。所以这个方案更适合目录结构固定、内容更新不频繁的场景比如纯展示型官网、单页应用的前端产物、静态资源服务器。折中的做法是把网站目录拆成两块——需要动态写的目录上传、缓存、session单独挂载一个可写分区其他静态文件和代码放只读分区。Linux的挂载机制天然支持这种拆分规划好路径即可。3.3 文件系统ACL作为补充除了传统的chmod/chownLinux还支持POSIX ACL访问控制列表可以对特定用户或组单独设置权限比传统的ugo权限模型更灵活。比如可以设置目录对www用户可读可执行但禁止www用户对 config 目录有写权限。setfacl -m u:www:r-x /var/www/html setfacl -m u:www:0 /var/www/html/upload/php # 禁止 www 用户访问ACL和chattr是不同层面的防护可以配合使用。ACL处理的是谁能写的权限逻辑chattr处理的是底层文件属性锁。从防篡改的角度ACL能让权限控制更精细适合多用户协作的服务器。4. 可信目录监控与文件指纹校验第一时间发现被改4.1 定期执行文件完整性校验光有防护还不够攻击是防不胜防的关键是要尽早发现。文件完整性校验是防篡改体系里最核心的检测手段原理也很简单给所有关键文件算一个哈希MD5、SHA-1、SHA-256都行定期重新计算并对比一旦发现哈希值变化说明文件被动过立刻报警。Linux系统本身自带一个非常好用的工具rpm -Va针对RPM系的CentOS/RHEL可以校验系统包内文件的完整性。但对网站目录这种自定义路径的文件更常用的是第三方工具。Tripwire是老牌的文件完整性检测工具优点是功能全、策略灵活缺点是配置复杂、上手门槛高新手容易在初始化上崩溃。AIDEAdvanced Intrusion Detection Environment相对更轻量配置简单我用的比较多。它核心概念是创建一个基准数据库baseline之后每次运行都跟基准库对比# 安装 yum install aide # CentOS/RHEL apt install aide # Debian/Ubuntu # 初始化基准数据库 aide --init mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz # 执行检查 aide --check基本思路是初始化时给所有受监控的文件建立哈希库之后定期比对。比对结果会列出所有变动的文件运维人员可以快速判断是正常更新还是被入侵了。不过要注意AIDE默认配置监控的是系统关键目录/etc、/usr、/bin等如果你要监控网站目录需要自己在配置文件里加规则。比如在/etc/aide.conf里添加/var/www/html CONTENT_EX其中CONTENT_EX表示检查文件内容、权限、所有者和扩展属性。具体宏定义可以看AIDE的man文档按需组合。4.2 更高频的方案inotify实时监控哈希比对有一个时效性问题如果只在每天凌晨跑一次攻击者上午篡改网页下午才能被发现中间这段时间恶意内容一直挂在线上。对重要系统来说这个窗口太长了。更好的方案是使用Linux内核的inotify机制做实时监控。inotify可以监控文件或目录的创建、写入、删除、移动、属性修改等事件事件一发生就触发报警几乎零延迟。用现成的工具的话最简单的是inotifywait。写一个简单的监控脚本inotifywait -mrq -e modify,create,delete,move /var/www/html --format %w%f %e --timefmt %F %T | while read event; do echo $(date %Y-%m-%d %H:%M:%S) $event /var/log/web_monitor.log # 在这里可以加告警动作比如发邮件、调用webhook done这个脚本可以直接用systemd服务或supervisor守护运行一旦网站目录下的文件被创建、修改、删除立刻记录日志并通知你。也可以直接用Python配合watchdog库做更复杂的告警逻辑比如排除某些正常写入的目录缓存目录、对特定文件类型的变更单独处理。我的建议是监控脚本做好白名单过滤否则缓存目录频繁写入会产生大量误报久而久之运维人员就麻木了真正被篡改的报警反而被淹没。4.3 云托管方案的对比与选型如果你用的是云服务器比如阿里云、腾讯云云平台一般会提供网页防篡改类的托管服务原理上和上面讲的类似但多了云端分析、自动恢复、木马查杀等能力部署也更省心。我整理了一个选型对比供参考方案检测能力防护能力自动化程度成本适用场景手动权限chattr无强防写入低零成本技术能力强的单人运维AIDE/Tripwire定期比对强事后检测无中零成本有定时任务习惯的团队inotify实时监控强实时检测无中零成本需要快速响应的场景云平台防篡改服务强实时云端分析强高按台收费对稳定性要求高的生产业务说实话云平台服务不是万能的它主要防护的是Web目录文件被篡改做不到把服务器上所有漏洞都堵住。如果你有预算又不想花太多精力维护可以上如果预算有限自己搭一套权限最小化 chattr inotify监控 离线备份的组合已经能覆盖90%以上的篡改场景。5. 备份与应急恢复被改了能秒级恢复5.1 备份策略设计的几个原则防篡改做到极致也挡不住零day漏洞和内部人员破坏。所以最后一道防线一定是备份。这里我不打算讲增量全量那一套理论就说几个我在实际中踩过的坑和总结出来的原则。第一备份必须异地。如果备份放在同一台服务器上攻击者拿到root权限后第一件事就是删备份、删日志。我的习惯是网站目录每天打成tar包通过rsync推送到另一台不相关的服务器或者云存储上。至少要做到服务器被人删干净了我还有一份独立于这台机器之外的数据。第二备份必须可恢复。光跑备份任务不算完至少一个月做一次恢复演练把备份恢复到一台临时机器上确认网站能正常打开、数据库能正常连上。我见过不少团队备份任务跑了半年真出事了一看备份文件全是坏的那时候真的欲哭无泪。第三保留历史版本而非只留最新。常见的备份轮转策略是日备保留7天、周备保留4周、月备保留3个月。这样即使某次备份的源文件本身已经被篡改了你还能找到更早之前的干净版本。5.2 应急恢复标准流程万一真的发现网页被篡改如果有一套标准流程恢复速度会快很多也能最大限度保留证据。我的推荐步骤是先隔离不急着删。把服务器从负载均衡摘掉或者直接在防火墙层面限制访问避免恶意内容继续对外传播。如果是被植入挖矿木马之类还要先排查进程占用情况。保存现场证据。保存当前文件列表、进程列表、网络连接、登录日志、Web访问日志。这些是后续溯源的基础一旦清理了就很难再找回来。定位并清除后门。用find找最近被修改过的文件、可疑的PHP文件find /var/www/html -name *.php -newermt 2025-01-01 -type f find /var/www/html -name *.php -exec grep -l eval\|base64_decode\|assert {} \;这条命令是我排查Webshell最常用的能快速定位可疑脚本。如果情况复杂建议把可疑文件下载到本地用安全工具在线扫描再分析。用备份恢复文件。从干净的备份里还原整个目录还原之后立刻执行一遍文件完整性校验确认没有残留后门。排查入侵途径修正配置。改密码、换密钥、升级组件、修补漏洞把这次入侵的根源解决掉否则恢复了也白恢复。5.3 自动化恢复的进阶玩法如果你对自动化有追求可以把第5.1节的inotify监控和备份脚本联动起来监控脚本发现文件被篡改后自动从备份目录拉取原始文件覆盖回去同时发送告警通知。这其实就是一个轻量级的自愈系统。需要注意两点一是自动覆盖要有防呆机制比如同一个文件的篡改超过N次就停止自动恢复转人工处理避免攻击者反复触发恢复、消耗服务器资源二是恢复动作本身要有日志记录方便事后复盘。我用过一个比较实用的组合inotifywait检测到变更 → 用rsync从备份目录找回原文件 → 写一条审计日志 → 触发告警webhook。Bash脚本大概几十行就能搞定不复杂。唯一的问题是误报率所以白名单目录排除一定要做否则缓存目录每次更新都触发一次恢复反而把正常文件覆盖掉了。6. 常见问题与排查技巧实录6.1 网页被篡改后这些隐患容易遗漏根据我的经验第一次被篡改的服务器往往存在多个隐患清理的时候很容易漏掉几个隐藏的Webshell用find搜php文件只是入门攻击者可能把一句话木马藏在图片里、藏在注释里、甚至改成非标准后缀配合解析漏洞使用。更稳妥的办法是在Web层禁用危险函数、禁止上传目录执行脚本让Webshell即使存在也跑不起来。可疑的定时任务攻击者为了维持权限经常会在crontab里写入反向shell或挖矿程序。检查方法很简单crontab -l cat /etc/crontab ls /etc/cron.d/ ls /var/spool/cron/SSH公钥后门检查~/.ssh/authorized_keys里有没有异常的公钥。攻击者拿到权限之后放一个自己的公钥下次就能以正常用户身份登录隐蔽性极强。隐藏进程与端口用netstat -antlp和ps aux检查异常的外连端口和进程。挖矿木马通常会有固定的矿池地址连接一看一个准。系统的别名和动态库劫持检查~/.bashrc、/etc/ld.so.preload这类位置有没有被塞入恶意内容攻击者可以通过这种手段隐藏自己的行踪。6.2 防篡改配置导致网站异常的处理防篡改搞得太严格最常见的翻车现场是网站突然出现500/403错误或者上传功能失效。遇到这类问题按这个顺序排查先确认是不是权限问题ls -l看文件属主和权限结合Web服务运行用户判断是否有访问权限。如果目录权限是700而Web用户不是属主就会403。再确认是不是chattr i锁定了目录用lsattr查看属性。如果上传目录被加了i上传功能必然报错把i去掉即可。确认SELinux状态getenforce如果是Enforcing看/var/log/audit/audit.log里有没有avc: denied的拒绝记录有的话就是SELinux在拦针对性地放行即可。确认PHP配置有没有误伤比如disable_functions里禁用了一些框架依赖的系统调用或者open_basedir没有包含必要的目录。我见过最让人哭笑不得的情况是有人为了防止篡改把整个网站目录都chmod 444了结果网站一访问PHP无法创建session文件所有用户全部掉线。所以做防篡改一定要最小化影响动态需要写的地方留好口子其他静态文件严格锁死。6.3 监控报警疲劳问题实时监控的最大敌人不是技术而是狼来了。如果你的inotify脚本对每次文件写入都报警而你的网站又频繁更新缓存、生成缩略图运维人员一天收到几百条告警两天之后就不看了真正被篡改的告警也会被忽略。这个问题必须从设计上解决对明显正常的写入目录缓存、临时、上传做白名单过滤。对高价值目录首页、后台入口、核心代码目录单独设置高优先级告警有变更立刻电话或短信通知。定期梳理报警规则把长期误报的规则删掉或合并。6.4 安全的坑不加盐的权限设置很多教程会让你直接chown -R www:www /var/www/html然后chmod -R 755 /var/www/html。我建议不要对整站目录一刀切因为总有些子目录需要写权限一刀切之后要么网站崩要么你为了省事直接给777。正确做法是自顶向下逐层收紧从根目录给一个基准权限然后对有特殊需要的子目录单独开权限# 根目录 755 chmod 755 /var/www/html # 上传目录单独设置属主改为 www mkdir -p /var/www/html/upload chown www:www /var/www/html/upload chmod 755 /var/www/html/upload7. 运维习惯与长期运营防篡改不是一次性配置而是长期运营能力。几条实用经验定期做一次Web目录的完整性校验建议至少每周一次如果业务变更频繁就提高到每天一次。校验结果要有日志方便对比和历史追踪。不是要你把所有文件哈希都打印出来而是关注差集——哪些文件在非运维操作时间发生了变更。安全补丁要跟上。Linux内核和Web服务、PHP、数据库这些核心组件定期更新安全补丁。我没见过哪个生产系统因为升级太频繁而被攻击的倒是见过不少因为懒得重启拖着不升级最后被漏洞利用的。关注Web中间件和依赖组件比如Nginx模块、PHP扩展、第三方库的安全公告。网页篡改往往不是Web服务器本身的问题而是某个不起眼的依赖组件被攻破了。最后是一条不太起眼但很重要的习惯每次发版、更新代码之后更新一次你的文件完整性基准库。否则你昨天发布的更新今天监控就报文件被篡改你还得手动验证其实是正常变更浪费时间不说还容易对真实告警丧失敏感度。8. 实操配置清单直接照着做我把前面讲的内容整理成一份可以直接照做的检查清单。如果你现在就需要给Linux服务器加防篡改能力按这个顺序往下走创建独立的Web运行用户useradd -r -s /sbin/nologin www调整网站目录权限收紧写权限上传目录单独处理chown -R root:www /var/www/html chmod -R 755 /var/www/html chown -R www:www /var/www/html/upload chmod -R 755 /var/www/html/upload在Web配置中禁止上传目录解析PHP。对首页和核心文件加chattr i目录不要加find /var/www/html -maxdepth 1 -type f -name *.html -exec chattr i {} \;部署AIDE初始化基准库配置定时检查任务每天凌晨执行。部署inotify监控脚本配置白名单目录和告警通知。配置异地备份策略rsync到远端或云存储每月做一次恢复演练。加固SSH禁用root登录、使用密钥、配置Fail2ban。检查PHP配置open_basedir、disable_functions、display_errors按前面说的调整。这些步骤全部做完快的半天慢的也就一两天。做完之后不要觉得万事大吉运维是一个持续对抗的过程攻防手段都在不断迭代定期复盘、定期演练才是不被篡改的最根本保障。