前言
最近几天在外面度假,度假的时候一查看我的电子邮箱,全是我的一个网站(非本站)的服务器掉线,又恢复的邮件告警通知,如图1所示。然后我登录服务器后台,一查看服务器的日志,CPU全部满载,内存占用也不乐观,整个服务器基本上都快死机了。
然后我一查服务器日志,Nginx中有大量的请求,明显是网站遭到了CC攻击。后来处理了半天,终于将让服务器正常运作了。现在我将这次事件复盘,并在我这个博客上写一下,希望能给大家一些参考。
什么是CC攻击
首先要弄清楚什么是CC攻击,这样才能更好的分析此次事件。CC攻击是一种通过大量HTTP/HTTPS请求来消耗对方服务器的算力资源,最终让服务器无法响应正常访客请求。
本次我被锤的网站的基本信息
这次被锤的不是本站,而是我的另一个博客,使用Mysql数据库,并使用wordpress,并未使用CDN,配置了限流措施。
第一次防御
这是我遭遇到的第一波的攻击的部分日志,先贴在这里
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:52 +0000] "GET /?qq=2061167119493570 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=8511898451795676 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2238.1529 Mobile Safari/537.36"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=6721716413828462 HTTP/1.1" 504 160 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=3304525546785436 HTTP/1.1" 502 150 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1"
38[.]97[.]116[.]245 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=6489259660797904 HTTP/1.1" 504 160 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1"
38[.]97[.]116[.]245 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=2143318243897064 HTTP/1.1" 504 562 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.3627.1503 Mobile Safari/537.36"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=2837409111227094 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.7415.1892 Mobile Safari/537.36"
38[.]97[.]116[.]245 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=4863682528019012 HTTP/1.1" 502 150 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:53 +0000] "GET /?qq=998863687202234 HTTP/1.1" 502 150 "https://blog.m78.su/" "Mozilla/5.0 (iPad; CPU OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:54 +0000] "GET /?qq=7192250860655180 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.4462.1504 Mobile Safari/537.36"
38[.]97[.]116[.]245 - - [11/Aug/2025:11:45:54 +0000] "GET /?qq=2849771918540818 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.4681.1855 Mobile Safari/537.36"
38[.]97[.]116[.]245 - - [11/Aug/2025:11:45:54 +0000] "GET /?qq=2456737518832016 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:54 +0000] "GET /?qq=1447076527184848 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0"
38[.]97[.]116[.]245 - - [11/Aug/2025:11:45:54 +0000] "GET /?qq=4280042494530612 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.8747.1906 Mobile Safari/537.36"
204[.]137[.]14[.]105 - - [11/Aug/2025:11:45:54 +0000] "GET /?qq=4122438966302322 HTTP/1.1" 504 160 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1"
38[.]97[.]116[.]245 - - [11/Aug/2025:11:45:54 +0000] "GET /?qq=8420392932370670 HTTP/1.1" 502 552 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.9429.1751 Mobile Safari/537.36"
162[.]210[.]173[.]17 - - [11/Aug/2025:11:45:55 +0000] "GET /?qq=7902625861800534 HTTP/1.1" 502 150 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/138.0.7204.119 Mobile/15E148 Safari/604.1"
可以从日志中看到,这些请求有一个共同的特征:使用了?qq=这个参数,后面跟上了一个随机的数字,请求是由不同的IP过来的。并且不同请求由不同的UA。虽然我这个被锤的网站没有上CDN,但是根据这个?qq这个请求参数,明显是为了绕过网站的CDN缓存(一般情况下,CDN并不会缓存有参数的请求)。
大量这些请求,导致我服务器过载,如图2所示。
我按照这些请求的特征,怀疑这是一个脚本小子在测试它的脚本,于是我给Nginx添加个设置,拒绝所有的请求参数为?qq的请求,配置项如下
if ($arg_qq) {
return 403;
}
当然,封禁IP肯定是少不了的,直接将这些攻击的IP段扔到UFW中,这些IP的请求一律丢包。限流措施肯定也是有的。
配置完成后,服务器压力直接断崖式下降。由图2的后一段可以看到。
第二次防御
好景不长,过了一段时间,服务器的压力又起来了。如图3所示。压力在几个小时之后,又陡然上升。
这次的请求日志如下
38[.]97[.]116[.]243 - - [11/Aug/2025:15:19:37 +0000] "GET /?tid=6535690580254364 HTTP/1.1" 200 14528 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.7666.1623 Mobile Safari/537.36"
38[.]97[.]116[.]242 - - [11/Aug/2025:15:19:37 +0000] "GET /?tid=3307915255666264 HTTP/1.1" 200 14529 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.9438.1269 Mobile Safari/537.36"
173[.]255[.]198[.]243 - - [11/Aug/2025:15:19:37 +0000] "GET /?tid=211988377641578 HTTP/1.1" 200 14525 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.8210.1479 Mobile Safari/537.36"
154[.]41[.]95[.]1 - - [11/Aug/2025:15:19:37 +0000] "GET /?tid=2620061088923674 HTTP/1.1" 200 14534 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Mobile/15E148 Safari/604.1"
154[.]41[.]95[.]1 - - [11/Aug/2025:15:19:38 +0000] "GET /?tid=1647749808894088 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36"
66[.]94[.]111[.]228 - - [11/Aug/2025:15:19:38 +0000] "GET /?tid=6174217870194440 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
23[.]184[.]48[.]78 - - [11/Aug/2025:15:19:38 +0000] "GET /?tid=5393241453263280 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.9388.1507 Mobile Safari/537.36"
38[.]135[.]24[.]31 - - [11/Aug/2025:15:19:38 +0000] "GET /?tid=6061369568712878 HTTP/1.1" 503 190 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1"
162[.]210[.]173[.]17 - - [11/Aug/2025:15:19:38 +0000] "GET /?tid=8884759786346032 HTTP/1.1" 503 190 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1"
38[.]97[.]116[.]242 - - [11/Aug/2025:15:19:38 +0000] "GET /?tid=2084403615746616 HTTP/1.1" 200 14528 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/28.0 Chrome/130.0.0.0 Mobile Safari/537.36"
162[.]210[.]173[.]17 - - [11/Aug/2025:15:19:39 +0000] "GET /?tid=3583947667680596 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.3294.1280 Mobile Safari/537.36"
38[.]97[.]116[.]243 - - [11/Aug/2025:15:19:39 +0000] "GET /?tid=3799061200322418 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.9506.1929 Mobile Safari/537.36"
23[.]184[.]48[.]78 - - [11/Aug/2025:15:19:39 +0000] "GET /?tid=6066805791296180 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.4554.1944 Mobile Safari/537.36"
38[.]97[.]116[.]242 - - [11/Aug/2025:15:19:39 +0000] "GET /?tid=2749828084235526 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.6865.1327 Mobile Safari/537.36"
可以看到,攻击者的IP可不止这些,IP防御措施是完全无效的。(如果有兴趣的话,读者可以尝试反向dns查询其中的部分IP,你可以惊喜的发现这些IP来自一个臭名昭著的匿名网络,这里不展开介绍,这个网络的发起者有一个对应的IP列表,你可以将IP下下来,然后,全部BAN了,是的,全部BAN掉)。
并且攻击者也换了一个请求参数,换成了?tid=这个请求了。这个时候,我能确认,我这次防御的对手不是一个低智能的脚本,有可能是真人攻击。当然,这一次我们故技重施,还是ban了所有查询参数为tid的请求。占用也是一下子降低下来了。
第三次防御
本来以为事情到此就结束了,但是没过多久,服务器CPU又被打高了,这次的攻击日志如下
66[.]78[.]40[.]182 - - [13/Aug/2025:00:13:40 +0000] "GET /?QaRMVEQ=551634187704194 HTTP/1.1" 200 14544 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.6918.1322 Mobile Safari/537.36"
66[.]78[.]40[.]182 - - [13/Aug/2025:00:13:41 +0000] "GET /?fQEVx=6327282624400830 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.1597.1144 Mobile Safari/537.36"
66[.]78[.]40[.]182 - - [13/Aug/2025:00:13:41 +0000] "GET /?mSr44sL=3369714067264006 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138[.]0[.]0[.]0 Mobile Safari/537.36"
66[.]78[.]40[.]182 - - [13/Aug/2025:00:13:41 +0000] "GET /?p8yLQqF=5617994542990974 HTTP/1.1" 200 14550 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 18_5_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/138.0.7204.119 Mobile/15E148 Safari/604.1"
66[.]78[.]40[.]182 - - [13/Aug/2025:00:13:41 +0000] "GET /?88YDWVsC=4633401310740444 HTTP/1.1" 200 14546 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2236.1028 Mobile Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:42 +0000] "GET /?7xiS4w5=2062967358205130 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.1109.1919 Mobile Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:42 +0000] "GET /?s93A3M=2378967981103654 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.8602.1661 Mobile Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:42 +0000] "GET /?FcleP=2051635042006308 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138[.]0[.]0[.]0 Safari/537.36 Edg/138[.]0[.]0[.]0"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:42 +0000] "GET /?r5h5PP=8466251285956912 HTTP/1.1" 503 190 "https://blog.m78.su/" "Mozilla/5.0 (iPhone; CPU iPhone OS 17_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Mobile/15E148 Safari/604.1"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:42 +0000] "GET /?UVK01R=8203045516367014 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.9250.1942 Mobile Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:42 +0000] "GET /?WMk9RVTR=7568131604327664 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.5695.1497 Mobile Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:43 +0000] "GET /?T3USQv=4733334234852802 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.4784.1042 Mobile Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:43 +0000] "GET /?Oc2vGa=7345017239055872 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.8345.1115 Mobile Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:43 +0000] "GET /?eVw344=4511229102615116 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137[.]0[.]0[.]0 Safari/537.36"
38[.]135[.]24[.]72 - - [13/Aug/2025:00:13:43 +0000] "GET /?UR2CYad=1267926096936682 HTTP/1.1" 503 592 "https://blog.m78.su/" "Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.5906.1845 Mobile Safari/537.36"
可以看到这一次的攻击的请求参数与请求值全部都是随机的,我之前的那一种暴力的按查询参数封禁方法没有效果了。(攻击者不断改进,这位锤我服务器的攻击者是真人的概率更高了)
刚好,同学也在论坛上问了下被CC怎么办,下面是论坛的网友给的部分提议:
网友1:直接关机 (这种方案不太好,感觉像直接当鸵鸟装死了)
网友2:祸水东引,请求全部重定向到别的地方 (这种行为也不太好)
网友3:使用cloudflare (我就用的这种方案)
网友4:博客转静态 (也是种不错的选择,可惜当时我在度假,这是一个麻烦的工程)
网友5:Ban IP (已经确认无效了)
刚好我那个网站的域名DNS早就托管在cloudflare上面了(否则的话网站转移到cloudflare是需要一段时间的),我这边直接打开cloudflare解析面板中的小黄云,当然,也在cloudflare的控制面版点击了 I’m under attack,给所有的请求来了一个人机验证。
过了几个小时之后,当所有的DNS全部更新完成,这些攻击请求全部都被cloudflare给拦住了。(打开了那个cloudflare代理开关到配置完全生效还是过了好几个小时,这几个小时我的服务器是仍然硬抗了所有攻击)
事后总结
虽然上了cloudflare后,那些攻击全部消停了,事后总结的时候,我发现这个防御仍然有不足之处。
首先就是,我的被锤了的网站的IP其实是漏了的(之前也没想到这个网站会被打),如果攻击者不刷新DNS的话,仍然能够锤我的源站(但是相应的,cloudflare提供了他们的所有的服务器IP段,我可以让我的服务器只处理来自这些IP的请求)
Cloudflare在国内的访问速度实际上是非常慢的,但是我这次很幸运,cloudflare分给我网站的服务器在国内访问速度蛮快(cloud flare如果给你分配了.1结尾的IP,那么你的网站在国内访问就会比较慢,这些IP被针对了)
而且有时候,我们被锤的站无法使用cloudflare,下面是我个人的防御构思
1、个人用户可以尝试使用雷池这种WAF进行防御(而且雷池官方提供了免费的IP黑名单地址,我看了下,这次捶我的IP都已经被雷池免费IP地址黑名单给标记了)
2、当然,如果有能力的话,我们可以找出攻击者的请求程序的JA3指纹(这个指纹与UA以及IP无关),可以选择性屏蔽,或者直接加JA3指纹的白名单。(但是这个需要自己写独立的代码了,接近自己手搓WAF了,很困难,但是也给攻击者上压力了)