看到页面被跳到陌生站点、搜索结果标题变成博彩或广告,先不要重装系统,也不要立刻去改 DNS。网站被劫持是一个结果,不是一个故障点:可能是域名解析被改,可能是源站被灌了跳转代码,可能是反向代理或 CDN 配置被动过,也可能只是你本地 hosts 或浏览器插件的问题。按“解析层 → 传输层 → 代理层 → 源站配置层 → 应用内容层 → 客户端”的顺序先定位,再动手,能避免改错地方、反复回滚。
先定层,再处置。用公共 DNS 与本地 DNS 分别解析域名,再用 curl 带 Host 头直连源站 IP,对比两者返回是否一致:解析结果与你在服务商控制台看到的不符,先查域名账户和解析记录;解析正常但页面仍跳转,问题在源站配置或站点代码。动手前先备份配置、站点文件和数据库,任何删除动作之前保留原始返回内容,方便回滚。
网站被劫持先定位在哪一层
分成六层看,每层都有对应的检查位置和判断依据,命中哪一层就只处理那一层。
- 域名解析层:检查位置是 DNS 服务商控制台的 A/AAAA/CNAME 记录,以及
dig +short A 你的域名 @8.8.8.8和dig +short A 你的域名 @223.5.5.5的输出。判断依据:解析出的 IP 不是你自己的服务器,或 NS 记录被换成陌生的域名服务器,说明问题在这一层。 - 传输/证书层:用
openssl s_client -connect 你的域名:443 -servername 你的域名 查看实际下发的证书。判断依据:签发者不是你申请证书的 CA,或有效期与你申请的不一致,说明 443 上应答的不是你的服务器。 - CDN / 反向代理层:检查位置是 CDN 控制台的“回源地址”“回源 Host”“源站协议”字段,以及响应头里的
server、via、x-cache。判断依据:直连源站 IP 正常,经 CDN 域名访问异常,问题在 CDN 配置或 CDN 账号。 - 源站 Web 服务配置层:执行
nginx -T(Apache 用apachectl -S加配置目录)看全部生效配置。判断依据:server 块里出现你没写过的return 301、rewrite指向陌生域名,或include了一个不认识的配置文件。 - 应用内容层:检查位置是数据库的站点地址字段、主题/模板文件、插件目录、页面里内联的 JS。判断依据:直连源站 IP 拿到的 HTML 里含陌生
<script>或跳转逻辑,说明代码被注入。 - 客户端:检查
/etc/hosts(Windows 为C:\Windows\System32\drivers\etc\hosts)、浏览器扩展、路由器 DNS 设置。判断依据:手机用蜂窝网络访问正常、只有某台电脑异常,属于客户端侧问题,不必改动服务器。
网站被劫持:先看这四个位置
第一处是日志。nginx 的访问与错误日志路径以 nginx -T | grep -E "access_log|error_log" 的输出为准,常见位置是 /var/log/nginx/access.log;系统登录日志在 Debian 系是 /var/log/auth.log,RHEL 系是 /var/log/secure;使用面板建站的,日志通常在面板的“网站日志”或站点目录下的 logs/ 里,以面板显示的路径为准。看两类东西:跳转状态码集中在哪些请求上,以及陌生来源 IP 的访问密度。
tail -n 2000 /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head
grep -aE '" (301|302) ' /var/log/nginx/access.log | tail -n 50第二处是命令输出,包括当前进程、监听端口、计划任务和 SSH 公钥。劫持通常需要持久化,计划任务和公钥是最常被忽略的入口。
第三处是配置项:/etc/nginx/nginx.conf 与 /etc/nginx/sites-enabled/、/etc/nginx/conf.d/,Apache 站点目录下的 .htaccess,以及应用自身的配置文件。第四处是面板字段:解析记录、回源设置、站点目录、伪静态规则、SSL 证书绑定、面板账号的登录记录与二次验证状态。
下面这段命令在源站以 root 执行,把 example.com 换成你的域名、1.2.3.4 换成源站 IP,执行后把现场一次性存档,后续所有判断都基于同一份材料,避免边改边测看不出差异。dig 需要先安装 dnsutils 或 bind-utils。

D=/tmp/incident-$(date +%F-%H%M); mkdir -p "$D"
dig +short A example.com @8.8.8.8 > "$D/dns-8.8.8.8.txt"
dig +short A example.com @223.5.5.5 > "$D/dns-223.5.5.5.txt"
dig +short NS example.com > "$D/dns-ns.txt"
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates > "$D/cert.txt"
curl -sSI -A 'Mozilla/5.0' https://example.com/ > "$D/headers.txt"
curl -sS -A 'Mozilla/5.0' https://example.com/ > "$D/index.html"
curl -sSI -H 'Host: example.com' http://1.2.3.4/ > "$D/origin-headers.txt"
nginx -T > "$D/nginx-T.txt" 2>&1
grep -nE 'return +30[1278]|rewrite|proxy_pass' "$D/nginx-T.txt" > "$D/nginx-redirect.txt"
crontab -l > "$D/cron-root.txt" 2>&1
ls -la /etc/cron.d/ /var/spool/cron/ > "$D/cron-dirs.txt" 2>&1
ss -lntp > "$D/listen.txt" 2>&1
cat ~/.ssh/authorized_keys > "$D/authorized_keys.txt" 2>&1网站被劫持:按可能性从高到低排除
排序依据是常见程度和处理成本,从上往下逐个排除,命中一个就处理一个,处理完再往下走,不要一次改多处。
- 站点代码或模板被注入跳转脚本(最常见)。确认动作:
grep -rIl --include='*.php' --include='*.js' -E 'eval\(|base64_decode\(|atob\(|fromCharCode' /var/www/站点目录 | head -n 50,再对照首页 HTML 与备份做diff。处理动作:从备份恢复被改文件,同时改掉后台、SSH、FTP、数据库的全部密码。只删文件不改密码,多半会被再次写入。 - 后台弱口令或插件漏洞被登录。确认动作:查应用自身的登录日志与用户列表(WordPress 可用
wp user list,其他 CMS 在后台用户管理页看最近登录时间)。处理动作:停用来源不明的插件与主题,升级到当前可用的稳定版本,加二次验证。 - 服务器已被入侵并留下持久化入口。确认动作:看第 2 节采集到的
cron-root.txt、authorized_keys.txt、listen.txt,以及在站点目录里查找最近被改动过的可执行文件:find /var/www/站点目录 -type f -name '*.php' -newermt '-7 days'(时间范围按你的实际情况调整)。处理动作:先备份再清理,把不清楚用途的入口全部移除;如果确认拿到了系统权限,仅清理文件往往不够,需要结合业务窗口评估重装。 - Web 服务配置被改。确认动作:
nginx -T | grep -nE 'return +30[1278]|rewrite|proxy_pass'逐条核对,看有没有跳到非自有域名的规则。处理动作:恢复配置备份,nginx -t通过后systemctl reload nginx。 - CDN 或反向代理配置、账号被改。确认动作:比对直连源站与经 CDN 的响应头和首页内容。处理动作:改 CDN 账号密码、开二次验证,核对回源地址与回源 Host 是否指向自己的源站。
- 域名解析被改或 DNS 缓存未刷新。确认动作:用两个以上公共 DNS 解析对比,用
dig +short NS 你的域名看 NS 是否被替换。处理动作:在注册商处改回记录、开启域名转移锁、开启登录二次验证;解析已改回但本地仍异常,是缓存未过期,看记录本身的 TTL 值再等。 - 客户端侧问题。确认动作:换一台设备、换一个网络访问同一域名。处理动作:清空本地 hosts 中的异常条目,禁用来源不明的浏览器扩展,改掉路由器管理密码与 DNS 设置。
网站被劫持:改完怎么确认真的解决了
先做直连验证,绕开代理和 CDN 看源站本身是否干净:curl -sI -H 'Host: example.com' http://1.2.3.4/ | head -n 5,期望看到 200 且没有指向陌生域名的 Location。再做公网验证:curl -sIL https://example.com/ | grep -iE '^HTTP/|^location',跳转链路上每一跳都应该是你自己的域名。最后做内容验证,把当前首页与备份对比:curl -sS https://example.com/ > /tmp/after.html; diff -u /root/backup/index.html /tmp/after.html | head -n 40。
页面验证之外,还要回过头看第 2 节那四个位置:crontab -l 与 ls -la /etc/cron.d/ 里没有再出现陌生任务,ss -lntp 没有多出你不认识的监听端口,nginx -T 里的跳转规则全部可解释。搜索引擎结果页的标题和摘要更新会滞后于站点本身,需要在搜索引擎的站长平台提交重新抓取,不要以搜索结果作为“是否解决”的第一判断依据。
观察时长取决于两点:DNS 记录的 TTL 和你站点的访问量。解析类改动建议至少观察一个完整的业务低峰到高峰周期,并在随后几天继续翻看访问日志与计划任务列表;配置和代码类改动建议连续观察 24 小时以上再撤掉临时防护。计划改解析之前,可以先把记录 TTL 调小,便于出问题时快速回滚,确认稳定后再调回原值,这一步只影响生效速度,不影响性能。
回滚必须在动手前准备好,而不是出问题后再想。改配置前执行 cp -a /etc/nginx /root/nginx-$(date +%F) 和 tar czf /root/site-$(date +%F).tar.gz /var/www/站点目录,改数据库前先 mysqldump 一份。回滚顺序是:先恢复 Web 配置并 nginx -t 校验后 reload;不行再恢复站点文件到改动前的压缩包;DNS 记录改动出问题时,把记录值改回原值即可,回滚前把你改前的记录值连同 TTL 一起记下来。任何一步回滚后,都要重跑上面的三条验证命令,确认恢复到改动前的状态再继续排查。