服务器CPU突然飙升到100%,网站响应时间从200毫秒拉长到5秒,用户打开页面像在看幻灯片。运维查遍应用日志和数据库慢查询都找不到原因,这种情况十有八九是被人植入了挖矿脚本。Web挖矿攻击不需要穿透内网,不需要提权,只需要在网页里插一段JavaScript代码,所有访问网站的浏览器都会变成攻击者的矿机。
挖矿脚本的检测难点在于它不像SQL注入那样会留下明显的错误日志,也不像DDoS那样会产生异常流量。它静悄悄地运行,只在浏览器端消耗CPU资源,服务端监控很难直接发现。但只要是程序就会有特征,本文从服务器指标、前端性能、网络请求、文件完整性四个维度,完整梳理挖矿脚本的定位方法。
服务器端的CPU异常模式识别挖矿脚本运行在客户端浏览器,服务器CPU不会直接升高,但会间接产生异常。第一个值得关注的指标是PHP-FPM或Node.js进程的响应时间分布。正常网站90%的请求在200毫秒内完成,如果突然出现大量请求耗时超过2秒,而且这些请求的URL都是正常的业务页面,不是某个特定接口,就说明问题出在浏览器端的资源消耗上。
用strace追踪一个响应变慢的PHP进程,会看到进程大部分时间处于空闲等待状态,而不是在计算。这说明服务器本身没在干活,是客户端处理页面时CPU被占满,导致后续请求发不出来或者发得慢。在服务器上运行top命令看到的CPU使用率可能不高,但用netstat查看TCP连接,会发现大量连接处于ESTABLISHED状态但长时间不传输数据,这就是客户端忙着挖矿没空发新请求的典型特征。
浏览器开发者工具的实时抓取打开Chrome的Performance面板,录制5秒页面运行情况。正常网页的JavaScript执行时间占比通常不超过30%,如果发现Scripting部分占比超过80%,而且调用栈里反复出现同一个匿名函数或者WebAssembly模块,基本可以确定是挖矿脚本。挖矿算法需要持续计算哈希值,调用栈会呈现规律性的循环模式,不像正常业务代码那样有间断和变化。
在Console面板里直接输入以下代码,可以快速检测当前页面是否存在异常的计算密集型操作:
(function(){
var start = performance.now();
var count = 0;
var timer = setInterval(function(){
count++;
if(count % 10000000 === 0){
var elapsed = performance.now() - start;
if(elapsed < 100 && count > 50000000){
console.warn('检测到异常高频计算,疑似挖矿脚本');
}
}
}, 0);
})();
这段代码的原理是检测浏览器是否能快速完成大量循环操作。正常页面即使有复杂计算也不会持续占用主线程,而挖矿脚本会让主线程一直处于饱和状态。如果控制台在3秒内就弹出警告,说明当前页面确实存在异常脚本。
网络请求层面的特征分析挖矿脚本通常需要连接矿池服务器,这个通信过程会在Network面板留下痕迹。筛选WebSocket连接,查看是否有连接到非业务域名的长连接。矿池地址通常使用非标准端口,比如3333、5555、14444等,而且WebSocket的通信数据量很小但频率很高,每隔几秒就发送一次小数据包。
更隐蔽的挖矿脚本会使用WebRTC或者通过代理中转,把矿池请求伪装成普通的HTTPS请求。这种情况下需要关注请求的Payload大小和频率。正常AJAX请求的Payload大小不固定,取决于用户操作。而挖矿脚本提交的工作量证明数据大小非常固定,通常在几百字节到几KB之间,而且每隔固定时间就会发送一次,这个时间间隔和矿池的难度设置有关。
用Chrome的Network面板导出HAR文件,然后用命令行分析请求间隔:
cat page.har | jq '.log.entries[].startedDateTime' | head -20
如果发现每隔30秒或60秒就有规律性的请求发出,而且请求的目标域名不在业务白名单里,就需要进一步排查。
文件完整性校验与源码比对挖矿脚本最常见的注入位置是公共JS文件,尤其是jQuery这类所有页面都会加载的基础库。攻击者会在文件末尾追加一行混淆过的代码,因为文件体积变化很小,运维很难注意到。检查方法是用版本管理工具的diff命令比对当前文件和原始版本:
diff /var/www/html/js/jquery.min.js /backup/clean/jquery.min.js
如果没有备份,可以从官方CDN下载同版本文件做MD5校验:
md5sum /var/www/html/js/jquery.min.js curl -s https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js | md5sum
两个MD5值不一致就说明文件被篡改过。但有些攻击者更狡猾,他们不修改静态文件,而是通过数据库注入把恶意代码存到网站配置表里,然后在页面渲染时动态输出。这种情况需要检查网站后台配置项,特别是统计代码、客服代码、广告位这些允许插入自定义脚本的地方。
进程级别的深度定位如果已经确认某个页面存在挖矿脚本但找不到具体代码位置,可以用浏览器的Coverage面板定位。打开Coverage面板后刷新页面,它会记录所有JavaScript文件的执行覆盖率。正常业务脚本的覆盖率通常在30%到70%之间,而挖矿脚本因为一直在循环执行,覆盖率会接近100%。按使用率排序,覆盖率最高但又不在业务代码清单里的JS文件就是重点怀疑对象。
还可以使用Chrome的Sources面板设置XHR断点,在所有网络请求发出时中断执行,然后查看调用栈。当断点命中一个来自陌生域名的请求时,调用栈会完整显示是哪个函数、哪个文件发起的请求,顺藤摸瓜就能找到挖矿脚本的藏身之处。
服务端日志的关联分析挖矿脚本被植入后,网站访问日志会出现一些反常模式。用awk统计每个IP的请求频率,会发现同一个IP在短时间内对同一页面发起大量请求,但请求间隔不均匀,这是因为挖矿期间浏览器响应变慢,用户会反复刷新页面。正常用户的刷新间隔是随机的,而被挖矿脚本拖慢的页面会导致用户刷新行为集中在3到5秒的超时区间。
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
另外,User-Agent字段也值得关注。挖矿脚本为了最大化收益,通常会排除爬虫和移动端,只针对桌面端浏览器运行。如果日志里某个时间段桌面端Chrome的访问占比异常升高,而且这些请求的停留时间特别长,可能就是挖矿脚本在作祟。
前端性能指标的突变监控建立前端性能监控体系是提前发现挖矿脚本的有效手段。在页面里埋点采集Performance API数据,重点监控三个指标:First Input Delay首次输入延迟超过500毫秒的占比、Long Tasks长任务超过50毫秒的执行次数、以及页面的总JavaScript执行时间。这三个指标任何一个出现突增,都应该触发告警。
具体实现可以在页面头部插入以下监控代码:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
console.warn('检测到长任务:', entry.duration, 'ms');
// 上报到监控系统
}
}
});
observer.observe({ entryTypes: ['longtask'] });
挖矿脚本会产生大量超过50毫秒的长任务,而且这些长任务的attribution字段会指向同一个脚本来源。通过持续监控Long Tasks的数量变化,可以在挖矿脚本被植入的几分钟内就发现问题,比用户投诉快得多。
第三方依赖的安全审计很多网站被植入挖矿脚本不是因为服务器被入侵,而是因为引用的第三方广告脚本、统计脚本、社交分享组件被供应链攻击污染。2018年英国政府网站和ICO官方网站的挖矿事件,都是因为引用了被篡改的第三方JavaScript库。
检查方法是打开页面的Sources面板,按域名分组查看所有加载的JS文件。重点关注不属于自己团队的域名,逐一检查这些域名的归属和脚本内容。对于广告投放系统,可以在Content-Security-Policy里限制script-src白名单,只允许信任的域名执行脚本。如果业务必须接入多个第三方脚本,至少要用Subresource Integrity校验外部脚本的完整性:
SRI哈希值不匹配时浏览器会拒绝执行该脚本,这样即使第三方CDN被篡改,恶意代码也不会在用户浏览器里运行。
应急响应与溯源处置定位到挖矿脚本后,第一件事不是删除代码,而是保留现场证据。把被篡改的文件复制一份,记录文件的修改时间、所属用户、权限信息。用stat命令查看文件的时间戳,和服务器登录日志做交叉比对,确定入侵时间点。
然后检查同时间段内所有被修改过的文件,攻击者通常会留后门,只删挖矿脚本不删后门等于白干。用find命令查找最近24小时内修改过的所有PHP、JS、HTML文件:
find /var/www/html -type f -mtime -1 \( -name "*.php" -o -name "*.js" -o -name "*.html" \)
清理完成后,排查入侵途径。常见的有弱口令SSH登录、CMS后台密码泄露、插件漏洞上传、以及Git仓库泄露导致的源码外流。检查authorized_keys文件是否有不明公钥,检查crontab是否有异常定时任务,检查/tmp目录是否有可疑的隐藏文件。这些步骤缺一不可,否则清理完挖矿脚本第二天又会卷土重来。
网站被植入挖矿脚本本质上是一场资源劫持,攻击者用你的用户设备为自己赚钱,你承担的是性能下降、用户流失和声誉受损的代价。定位方法的核心思路是从现象倒推源头,CPU异常是现象,网络请求是线索,文件变更是证据,三个维度交叉验证就能快速锁定恶意代码的位置。
