网站被百度收录了半个月才有人发现快照已经被劫持成菠菜页面,流量掉了一半还在正常更新内容。扒开JS劫持、PHP后门、Nginx代理转发、DNS篡改四种劫持方式,最容易漏掉的是第三种
一个做了两年的站,每天正常更新文章,每天正常查看流量统计,看起来一切正常。直到有一天用百度site命令搜了一下,发现快照里显示的不是自己的页面内容,而是一堆赌博、色情的诱导文案。这时候去看后台,没有被登录的记录,FTP文件修改时间也对不上,服务器负载也没异常——但百度收录里确实已经全是垃圾内容了。
这就是网站劫持最让人头疼的地方:你看自己的网站一切正常,百度看到的却是另一个版本。等发现的时候,快照已经被污染了十天半个月,收录掉了、排名掉了、流量掉了一半,修复起来不光是清后门的问题,还得向搜索引擎提交快照更新、申请恢复收录,整个过程少则一周多则一个月。
四种劫持方式一句话识别
| 1 | JS劫持 — 正常用户看不到,只有搜索引擎蜘蛛(或特定UA)访问时才跳转。F12看源码没有异常,因为劫持代码在服务端判断UA后动态注入 |
| 2 | PHP后门/Webshell劫持 — 攻击者在网站目录里写了一个隐藏的PHP文件,通过URL参数触发,向蜘蛛返回篡改后的页面内容 |
| 3 | Nginx/Apache配置劫持 — 服务器配置文件被篡改,对来自搜索引擎的请求做反向代理或301跳转。代码和文件都没问题,是服务器层面被动了手脚 |
| 4 | DNS劫持 — 域名解析被篡改,用户访问你的域名时被导向攻击者的服务器。这种通常配合其他劫持方式一起用,影响范围最大 |
一、JS劫持:专门骗蜘蛛,正常人看不到
JS劫持是目前最常见的一种方式。攻击者的逻辑很简单:在页面代码里注入一段JavaScript,判断当前访问者是不是搜索引擎蜘蛛。如果是普通用户(Chrome、Edge浏览器),正常显示页面内容;如果是百度蜘蛛(Baiduspider)或谷歌蜘蛛(Googlebot),就执行跳转或展示菠菜/色情内容。

判断UA是蜘蛛后,常见做法有三种:直接302跳转到攻击者的目标页面;用document.write覆盖整个页面内容;通过隐藏iframe加载目标页面。最后一种最隐蔽,因为蜘蛛抓取时会同时抓取iframe里的内容作为快照素材,而正常访问时iframe是隐藏的。
JS劫持为什么不容易被发现
· 你用浏览器打开网站,看起来一切正常——因为你不是蜘蛛UA
· 你看网页源码,可能也看不到异常——因为劫持代码是动态注入的,不在静态HTML里
· 你看服务器日志,访问记录正常——因为攻击者根本没登录你的服务器
· 唯一的线索在百度快照里——但谁天天去看快照?
排查JS劫持最有效的方式不是看源码,而是模拟蜘蛛的UA去请求页面。用curl带上Baiduspider的UA去请求你的页面URL,看返回的HTML里有没有异常的JS代码或跳转逻辑:
curl -A "Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)" https://你的网站.com/如果返回的内容和你浏览器看到的完全不一样,那大概率就是JS劫持。这个方法对Googlebot也一样适用,把UA换成Googlebot就行。
二、PHP后门/Webshell:代码里藏了个开关
这种方式的攻击路径通常是:攻击者通过主题漏洞、插件漏洞、弱密码爆破等方式,在你的网站目录里写入一个隐藏的PHP文件。这个文件平时什么都不做,但当请求中包含特定参数时(比如?hijack=1),它就会劫持整个页面的输出。
典型的后门代码会挂在WordPress的index.php、wp-config.php、functions.php等核心文件里。有的更隐蔽——把后门代码编码成base64,塞在某个不常用的插件文件里,文件名伪装成.jpg或.png,内容却是PHP代码。
排查后门的三个关键位置
· 主题目录下的functions.php(劫持钩子注入)
· wp-content/uploads/目录下不该存在的.php文件
· .htaccess文件里的RewriteRule(把蜘蛛请求转发到后门脚本)
· 最近修改过的文件列表:find . -mtime -7
后门代码的常见伪装
· base64_decode包裹的eval执行
· 文件名伪装:shell.php.jpg(利用双扩展名绕过检查)
· 隐藏属性:chattr +i 锁定文件防止被删除
· 定时任务:crontab里写入定期拉取远程后门代码的wget命令
Webshell的排查比JS劫持复杂,因为后门可以藏在任何地方。建议用Wordfence或Sucuri Scanner这类安全插件做全站文件扫描,它们会对比WordPress官方文件仓库的原始哈希值,找出被修改过的文件。但注意,扫描插件只能检测已知的后门模式,高度定制化的后门可能漏过。
三、Nginx/Apache配置劫持:最容易漏掉的一种
这是四种方式里最容易被忽视的。前面两种劫持(JS注入、PHP后门)发生在网站代码层面,你会去查文件、查源码、查插件。但Nginx配置劫持发生在服务器层面——代码没问题、文件没问题、数据库没问题,问题出在服务器的配置文件中。
攻击者如果拿到了服务器的root权限(哪怕只是Nginx的运行用户权限),就可以在nginx.conf或站点配置文件中加一段反向代理规则:当请求来自搜索引擎蜘蛛时,把请求转发到攻击者的服务器上获取篡改后的内容,再返回给蜘蛛。整个过程你的网站代码完全没被修改,Wordfence之类的插件根本检测不到。
# nginx.conf 中被注入的劫持规则(示例)if ($http_user_agent ~* "Baiduspider|Googlebot") {proxy_pass http://攻击者服务器/劫持页面/;break;}为什么Nginx配置劫持最难发现
· 你检查所有PHP文件——没问题,因为劫持不在PHP里
· 你跑一遍安全插件扫描——没问题,因为扫描不检查Nginx配置
· 你浏览器打开网站——没问题,因为你是正常UA,不是蜘蛛
· 你用curl不加UA测试——也没问题,因为默认curl的UA不会被匹配
· 只有用蜘蛛UA去请求,才能发现异常
排查Nginx配置劫持的核心是检查所有conf文件里有没有不认识的proxy_pass、rewrite、return 301/302规则。特别是那些根据$http_user_agent做判断的条件语句。Apache用户也一样,检查.htaccess和httpd.conf里有没有可疑的RewriteCond匹配User-Agent的规则。
四、DNS劫持:影响范围最大的全局攻击
DNS劫持和前面三种本质不同。JS注入、PHP后门、Nginx配置劫持都是在你的服务器上动手脚,而DNS劫持是在域名解析环节动手脚——攻击者把域名的解析记录改成了自己的IP地址。这意味着所有访问者(包括蜘蛛和真实用户)都会被导向攻击者的服务器。
DNS劫持通常有两个入口:域名注册商账号被盗(改了DNS解析记录)或本地DNS缓存投毒(在运营商的DNS服务器上注入了虚假记录)。前者只要保护好域名注册商的登录密码和二次验证就能防住,后者你个人几乎无能为力,只能靠DNSSEC来从协议层面验证解析结果的真实性。

| 劫持类型 | 攻击位置 | 正常用户能看到异常吗 | 排查难度 | 关键检测方法 |
|---|---|---|---|---|
| JS劫持 | 网站代码 | 看不到 | 中等 | 用蜘蛛UA curl请求,对比正常UA返回 |
| PHP后门 | 网站文件 | 看不到 | 较高 | 全站文件哈希扫描、最近修改文件列表 |
| Nginx配置劫持 | 服务器配置 | 看不到 | 最高 | 检查nginx.conf里的proxy_pass和RewriteRule |
| DNS劫持 | 域名解析 | 能看到 | 中等 | 多节点DNS解析查询、对比不同DNS服务器结果 |
五、怎么第一时间发现劫持:监控方案
前面讲的是已经中招了怎么排查,但真正的重点应该是怎么在流量崩掉之前就发现。等百度收录掉了一半再去修,成本远高于提前监控、及时处理。下面是三种不同投入层级的监控方案:
零成本方案:定时脚本+蜘蛛UA检测
写一个Shell脚本,每天自动用Baiduspider和Googlebot两种UA去请求首页和关键内页,用diff对比两次返回的HTML差异。如果差异超过阈值,发邮件/钉钉/企业微信告警。脚本放crontab里每天跑一次,基本不花钱。
半自动方案:免费在线工具组合
· 拨测boce.com的劫持检测:输入URL即可检测多节点访问是否被劫持
· VSPing的域名劫持检测:检测DNS劫持和域名污染
· 百度站长平台的安全检测:检测网站是否存在被黑、挂马等风险
· Google Search Console的安全问题报告:Google主动通知你网站被入侵
持续监控方案:专业工具
· Wordfence(免费版可做文件完整性扫描和恶意代码检测)
· Sucuri SiteCheck(免费在线扫描+付费版持续监控)
· SiteGuarding / Quttera(专门做恶意软件和黑链检测)
· 自建web-monitor页面篡改监控(开源,定时对比页面哈希)
如果管着多个站,推荐把监控做成统一的看板。每个站点都配一个定时任务,每天自动跑蜘蛛UA检测+页面哈希对比+收录数据快照。任何异常都汇总到一个地方,而不是分散在各个站的独立日志里。
六、发现劫持后的恢复流程
发现劫持后,顺序很重要。很多人一发现劫持就立刻改密码、删文件、重装系统——但这样反而可能销毁了排查线索。正确的顺序应该是先取证、再止损、最后恢复。
| 步骤 | 操作 | 关键点 |
|---|---|---|
| 1 | 截图保存百度快照、Google缓存 | 作为证据,也方便后续分析劫持方式 |
| 2 | 用蜘蛛UA curl抓取首页和关键页面,保存HTML | 对比正常UA返回的HTML,定位劫持注入点 |
| 3 | 检查服务器最近修改的文件和新增文件 | find /网站目录 -mtime -30 -type f | sort |
| 4 | 检查nginx.conf、.htaccess和crontab | 特别注意$http_user_agent条件判断和crontab里的wget/curl |
| 5 | 全量备份当前状态(含被篡改的文件) | 保留现场,方便安全团队后续分析攻击路径 |
| 6 | 清除后门、恢复配置文件、修改所有密码 | 包括FTP/SSH/数据库/WordPress管理员/域名注册商 |
| 7 | 向百度站长平台提交快照更新申请 | 百度站长→站点管理→快照更新→提交URL列表 |
| 8 | 在Google Search Console提交安全审核 | 安全问题→请求审核→说明已清除恶意内容 |
第6步"修改所有密码"看起来像是废话,但实际执行时漏掉一个账号的案例太多了——改了服务器密码但没改WordPress管理员密码、改了数据库密码但没改FTP密码、改了所有密码但没改域名注册商密码。攻击者只要保留任何一个入口,清除后门之后很快又会被重新植入。
恢复过程中容易漏掉的三件事
· 百度站长平台的死链提交:劫持页面被百度收录后,修复了原页面但劫持URL还在索引里,需要提交死链规则让百度删除
· CDN缓存清理:如果用了CDN,劫持期间CDN节点可能缓存了篡改后的页面,需要全站刷新CDN缓存
· 第三方统计代码检查:有些劫持会替换百度统计或Google Analytics的跟踪代码,导致流量数据失真
七、预防比监控更重要
监控能帮你第一时间发现问题,但防住攻击才是根本。网站被劫持的入口80%集中在以下几个地方,把这些堵住,劫持成功率会大幅降低:
WordPress主题和插件
不用破解版主题/插件(后门高发区),不用来路不明的免费主题,所有插件保持更新。关键文件(wp-config.php、.htaccess、functions.php)设成只读权限(chmod 444)。
密码和权限管理
所有后台账号开二次验证(WordPress管理员、域名注册商、服务器SSH、数据库),不同站点用不同密码,定期轮换。服务器上不要用root跑Web服务。
文件完整性监控
用Wordfence或手动脚本对核心文件做哈希快照,任何非预期的文件变更立即告警。这个比页面内容监控更底层——后门一写入就能发现,而不是等到快照被污染了才知道。
域名注册商安全
开启注册商锁(Transfer Lock),开启登录二次验证,关闭API密钥(如果不用DNS管理API的话)。DNS解析用DNSSEC防止缓存投毒。
站群场景下,一个站被劫持了还可能牵连到同一台服务器上的其他站点——因为攻击者拿到的是一个站的后台权限还是整台服务器的权限,取决于你的站点隔离做得怎么样。每个站独立FTP账号、独立数据库、独立文件目录,能做到的话安全性会好很多。
在UC建站系统里,劫持监控是收录监控体系的一部分。每个站点发布内容后,系统会自动记录百度快照时间戳和收录URL列表。定时任务用蜘蛛UA模拟抓取页面,对比预期内容和实际返回内容之间的差异。一旦快照内容和预期不符、收录URL异常增长、页面哈希发生变化,立即生成告警通知。把"每天手动site查一次"变成了"系统自动跑、异常自动推",不用再靠人工巡检来发现劫持。
网站劫持这件事,最让人难受的不是它发生了,而是发生之后很久你才知道。一个站被劫持半个月,百度收录里已经全是垃圾内容,恢复收录少说一个月。但如果你每天用蜘蛛UA跑一遍关键页面、每周做一次文件完整性扫描、每个月检查一次Nginx配置和crontab,劫持还没造成实质伤害就会被发现。投入的成本是一个Shell脚本加一个crontab条目,避免的损失可能是半个月的流量和两个月的收录恢复期。
