☰
深入解析CC攻击:原理、识别与分层防御实战
2026/10/13 3:51:45 网站建设 项目流程

干网站运维和后台开发的,应该都经历过那种莫名其妙的心跳加速:业务量没涨,服务器CPU却飙到了90%,登录接口超时,首页都打不开,数据库连接池被打满,开发群里一片哀嚎。查了一圈,带宽没跑满,机器没宕,就是请求量大得离谱,而且访问模式看着“挺正常”。这种场面,大概率就是撞上CC攻击了。

CC攻击这个词,搞安全的肯定不陌生,但大多数人一开始都迷糊,因为它不像DDoS那样直接“灌流量”把链路塞死。它模拟的是真实用户行为,用看似合法的请求去耗尽服务器资源。这活儿最阴的地方在于:你很难在第一时间判断这是“业务突然火爆”还是“被打了”。这篇东西,我想把CC攻击的本质掰开揉碎了讲清楚——它盯上的是服务器身上哪块肉,日常工作里怎么把它和真实流量区分开,防线上哪些参数才是真正能救命的。干运维、做后端、写接口的人看到这篇文章,应该能少走不少弯路。

1. 先搞清楚CC攻击到底在消耗什么

很多人把CC归到DDoS里,其实它俩路数完全不同。DDoS里最常见的UDP Flood、SYN Flood,目标是把带宽和网络设备打满,本质上是“量”的战争。CC攻击不一样,它走应用层,用的是HTTP这种正经协议,打的是服务器内部的处理能力。你要理解它,首先得搞清楚它真正在消耗的资源是什么。

1.1 它和带宽型DDoS的区别

打个比方你就明白了。把服务器当成一个银行柜台,正常用户办业务是排队取号、到窗口办理、办完走人,整个过程有快有慢,但柜台基本忙得过来。

带宽型DDoS是什么?是外面涌入大量的人,把银行门口那条马路彻底堵死,交警进不来,客户也进不来,再多的柜台也白搭。这是网络层的招数。

CC攻击呢?是马路完全畅通,但进来的人不取号、不排队,直接冲到柜台前“你好、你好、你好”地反复问同一个问题。营业厅门口保安拦不住,因为人家确实是来“办业务”的。一个两个无所谓,几千个窗口同时被这种“客户”占住,真正想办事的正常用户反而排不上队。这就是应用层攻击的可怕之处,它不堵路,直接堵柜台。

所以两者的核心差异是:

  • 带宽型攻击的指标是流量大小,单位是Gbps,目标是打满链路。
  • CC攻击的指标是请求速率和并发数,单位是QPS或者在线连接数,目标是耗尽服务器资源。

带宽型攻击你可能通过扩容链路、加高防机房就能缓解,CC攻击就算链路空到不行,服务器照样可能被打趴。这也是CC攻击特别烦人的原因:你按传统DDoS的思路去防,完全使不上劲。

1.2 被消耗的资源清单

理解了攻击逻辑,再来看看它具体盯上的是什么资源。我列一份清单,按顺序排查的时候照着看就行。

  • TCP连接表:服务器对每个TCP连接都要维护一个文件描述符和一个内存结构体,连接数多了就直接内存吃紧。特别是慢速型的CC攻击,一个连接挂着不释放,几分钟就能占用大量连接资源。
  • HTTP处理线程/进程:不管是Apache的进程模型还是早期PHP的FastCGI方式,一个并发请求就要占据一个工作线程。线程数是有限制的,占满了之后,新请求就只能排队等待。
  • CPU上下文切换:请求一多,CPU就要频繁在进程、线程之间切换,大量时间耗在切换调度上而不是真正处理业务,表现为CPU使用率不高但系统负载(Load Average)奇高。
  • 数据库连接池:这是重灾区。一个搜索接口、一个列表页查询,每一次请求都去连数据库,连接池就那么几十个连接,攻击请求直接把连接池占满,正常用户的数据查询全部阻塞。
  • 磁盘I/O与缓存:高并发下日志要写盘、Session要读写、文件要读取,都会压到磁盘I/O上。缓存没做好的话,每一次请求都穿透到后端存储,I/O很快就到瓶颈。

很多团队第一次排查CC攻击,盯着带宽图看了半天,发现网卡流量才几个Gbps,就排除了攻击的可能。但恰恰忘了看CPU、看连接数、看数据库的活跃连接。这几个指标在CC攻击下一定会出现异常的联动,只是顺序有先后。

1.3 成本不对称是CC攻击流行起来的根本原因

CC攻击之所以这么泛滥,说白了就是“成本不对称”四个字。攻击者那边,伪造一个HTTP请求的成本极低,低配的机器、普通的家庭带宽就能每秒发几十上百个请求。但服务器这边,处理一个合法请求要干的事情可就多了——解析协议、路由分发、鉴权校验、业务逻辑运算、数据库查询、模板渲染、日志记录,一顿操作下来消耗的资源是请求本身的几十上百倍。

有人算过账,一台普通的攻击端机器,能拖垮一台配置是它几十倍的服务器。这种产出比,决定了CC几乎成了网络攻击里性价比最高的打法。你看很多个人站点、小企业业务系统,平时没人关注,某天突然收到大量请求,一查就是几百个代理IP在轮番访问某个接口,这就是典型的低成本捣乱。

理解了这个成本不对称,你也就理解了后面所有防御策略的出发点:要么增加攻击者的成本,要么降低己方的消耗。所有防护思路,都是围绕这两个方向展开的。

2. 三类最常见的CC攻击变体和识别特征

CC攻击不是只有“高频请求”这一种玩法。我这些年排查线上告警,实际遭遇的几乎可以归结为三类。每一类的攻击原理、流量特征、排查抓手都不一样,分开讲能帮你更快对症下药。

2.1 高频请求型:直来直去的流量碾压

这是最原始也最常见的形态。攻击者借助工具或者代理池,针对某个URL或者一批URL发起高频HTTP请求。特征非常明显:

  • 同一时间段内,某个URL的请求量出现几十上百倍的激增。
  • 来源IP很分散,可能是几个C段,也可能是随机分布。
  • 请求头里面User-Agent、Referer往往比较单一,或者虽然随机但规律明显(比如按字典排序)。
  • 请求的URL高度集中,访问的资源顺序也特别机械,不像真人浏览那样有深度和跳跃。

这种攻击技术含量最低,但效果直接。尤其是那些SQL查询开销比较大的接口,几个并发不高但持续不断的请求就能把数据库拖垮。识别方法也简单,拉一份Access Log,按URL分组统计一下请求数,一下子就能看到热点。

2.2 慢速连接型:把连接池一点点耗尽

这类攻击更狡猾,它不追求高请求量,反而故意“慢慢来”。原理是利用HTTP协议的特性:客户端发起连接后,一直以极低的速度发送数据,或者发一部分就停住,让服务器一直等待。一个连接就这么占着线程和内存资源不放,几千个这样的连接就能把服务器的并发处理能力吃干抹净。

典型特征是:

  • 服务器并发连接数持续攀升,但QPS并不高。
  • 网络流入流量很小,可能只有几Mbps。
  • CPU使用率不一定很高,但新用户访问明显卡顿,甚至直接拒绝连接。

这种攻击在日志里比较难发现,因为它可能根本没完成一个完整的请求。你得看服务器当前的TCP连接状态,统计一下处于ESTABLISHED状态的连接数,再看这些连接的保持时长和发送字节数。正常情况下,没有哪个真实用户会在一个页面上挂着一个TCP连接几分钟还不发送完整请求的。

2.3 业务定向型:专挑“贵”的接口打

这是进阶玩法。攻击者明白,不是所有接口都值得打,只打那些“处理成本高”的接口就能用最小的请求量达到最大的杀伤效果。我见过被打的接口大概有这么几类:

接口类型消耗的资源典型场景
搜索接口数据库模糊查询、索引扫描电商搜索、站内检索
登录接口密码哈希、数据库读写、验证码校验用户登录、找回密码
文件下载磁盘I/O、带宽占用报表导出、大文件下载
列表查询接口数据库排序、分页统计订单列表、消息记录
短信发送接口第三方服务费用、频率控制注册、验证码短信

业务定向攻击更隐蔽,因为请求量看起来不高,单个IP的频率也在“正常范围”,但架不住代理池换着IP打一个接口。它消耗的不仅是服务器资源,还可能是真金白银——短信接口被打,费用哗啦啦地流出去,这种损失你事后查账单才反应过来。

这个类型的攻击,光靠看带宽、看QPS这些宏观指标是发现不了的。必须盯着接口维度的响应时间、数据库慢查询日志、缓存命中率这些微观指标。如果某个平时只要50ms就能响应的接口突然平均耗时到了2秒以上,且没有发版变更,那就要高度警惕了。

3. 区分正常流量和攻击流量的核心难点

搞明白攻击形态之后,最头疼的问题来了:怎么把攻击流量从正常流量里摘出来?这是所有防御方案的命门。CC攻击之所以难防,就在于它装得太像了。但“像”不等于“是”,行为层面的差异怎么都藏不住。

3.1 攻击者如何伪装成“活人”

现在的攻击工具早就升级了,不再是早年那种赤裸裸的裸奔请求。它们会随机生成User-Agent,伪装成Chrome、Safari的各种版本;会带上伪造的Referer模拟从搜索引擎点过来的路径;会加载Cookie模拟会话状态;会随机化URL参数避免撞上WAF的规则指纹。

更厉害的会集成一个庞大的代理池,每个请求都换一个IP,频率控制在单个IP每分钟几次的水平——这和你办公室一个网段十来个同事访问的频率差不多。单看某一个IP,完全看不出异常。

我见过一次真实案例,攻击方甚至把请求分布做得和业务高峰期的曲线高度重合,白天少打,夜里猛打,就是为了让流量基线对比看起来“正常”。这种情况下,如果你只做IP粒度的频率限制,效果几乎为零。

3.2 行为特征才是有效的判断维度

那怎么破?光看单点不够,就得看“群体行为”和“时间规律”。

  • 单位时间内的IP离散度:真实用户的访问,集中在固定时间和固定地理区域,IP离散度相对稳定。攻击流量哪怕用了代理池,离散度也容易失控,同一秒内出现几百个新IP开始访问同一个URL,这在真实业务里几乎不可能。
  • 请求间隔的统计学规律:真人操作的请求间隔是随机的,有人快有人慢,整体分布自然。机器请求的间隔要么很均匀(定时器触发),要么集中在某个固定范围。
  • Session的点击路径深度:正常用户会从首页进列表页,再看详情页,有先后逻辑。攻击请求通常直击目标URL,没有前置页面,也没有后续跳转,深度为1。
  • 流量潮汐特征:正常业务有明确的潮汐——早上流量爬坡、深夜回落、周末和节假日有规律波动。攻击流量往往是全天平均发力,或者专门挑凌晨2点到5点这种业务低谷期。

这些维度和单IP频率限制配合起来,才能组成一个相对可靠的判定体系。这也是现在主流WAF产品做“行为分析”模块的逻辑基础——不再看“你是谁”,而是看“你怎么访问”。

3.3 流量基线的价值

说到这必须提一嘴流量基线。没有基线,你连“异常”都定义不了。我接手过的系统里,凡是建了流量基线的团队,遇到CC攻击的响应速度都明显更快——因为基线数据可以直接触发告警,不用等用户反馈“打不开了”才知道出事。

基线要记录什么?至少要包括这几项:总QPS的分钟级均值、各核心URL的请求量分布、活跃IP数、各接口的P95响应时间、错误码比例。持续记录一段时间(至少两周),就能形成一套指标的正常范围。之后任何一个指标偏离基线的倍数超过阈值,就有了提前预警的依据。

我自己的习惯是设置两级阈值:超过基线3倍触发提醒,超过10倍触发告警并自动开启防护策略。实际用下来,比起单纯依赖防火墙规则,这个方案能提前5到10分钟发现问题。别小看这几分钟,对防御来说,早介入5分钟可能就是少打几百台机器的问题。

4. 从边缘到源站的分层防御落地

理解了攻击的本质和特征,防御就不是什么玄学了。现在的主流做法是分层设防,从流量到达源站之前就开始拦截。我把自己的落地经验按层次拆一下,每一层解决什么问题、需要配什么参数,都给你列清楚。

4.1 边缘清洗与源站隐藏

第一层防线是边缘。域名的DNS解析不要直接指向源站IP,而是接到CDN或者云WAF上。这么做有双保险的意味:CDN把静态资源缓存到边缘节点,大量针对静态文件的CC请求直接在边缘就消化掉了,根本到不了源站;WAF则可以在边缘对请求做规则过滤和行为分析。

源站隐藏是最容易忽略但最重要的操作。如果你源站IP泄露了,攻击者完全可以绕过CDN直接打源站IP,前面的防护全部形同虚设。我见过一个客户,域名在CDN前面好端端的,结果源站IP泄露,攻击流量直接绕开CDN灌到了源站,坚挺了没两个小时就宕了。

源站隐藏的基本要求是:

  • 源站不对外直接解析域名,只用IP传输,且IP不回源给任何第三方。
  • 在源站侧配置访问控制,只允许CDN厂商的回源IP段访问,其他来源一律拒绝。
  • 关闭源站服务器上所有非业务端口的外网访问,只保留80、443。

这些操作在配置上不复杂,但重要性排第一,优先级高于任何限流策略。源站IP一旦裸奔,其他层次都是空中楼阁。

4.2 限流参数配置实操

第二层就是限流。限流分两个维度:一个是按IP的速率限制,另一个是按会话/Cookie的频率限制。IP维度防单点突发,会话维度防代理池伪装。两个结合起来才比较完整。

以Nginx为例,按IP做限流是非常成熟的方案,我直接给一套能抄的配置:

# 定义限流区域:按客户端IP限制,速率20r/s,内存10M limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=20r/s; # 定义按会话Cookie的限流区域,速率为5r/s limit_req_zone $cookie_session_id zone=req_limit_per_session:10m rate=5r/s; server { listen 80; server_name example.com; location / { # 允许每个IP突发40个请求,超出就走延迟 limit_req zone=req_limit_per_ip burst=40 nodelay; # 会话维度限流 limit_req zone=req_limit_per_session burst=10; proxy_pass http://backend; } # 对登录、搜索等高成本接口做更严格限制 location /api/search { limit_req zone=req_limit_per_ip burst=10 nodelay; limit_req zone=req_limit_per_session burst=5; proxy_pass http://backend; } }

参数怎么理解?rate=20r/s表示每秒平均放行20个请求,超过的部分进入burst缓冲区,缓冲区是40个,nodelay参数的意思是一旦缓冲区满了,直接返回503,不做排队等待。$cookie_session_id这一行是按会话ID限流,防止同一个账号在短时间内高频调用接口。

这里有个设计经验:IP限流的速率不能设得太死,不然学校、公司这种大量用户共享出口IP的场景会误伤一片。我一般基准是普通接口IP限流50r/s到100r/s,核心高价接口10r/s到20r/s,再配合会话维度做二次校验。另外burst参数不宜太大,给个20到50就足够应对正常的瞬时冲高,太大的话攻击流量也会被放进来排队。测试下来这个参数区间在大多数业务上表现都比较稳。

4.3 人机校验的动态开关

第三层是人机校验。限流只能控制超频请求,但是分布式代理池可以把每个IP的请求频率压得很低。遇到这种情况,靠限流是挡不住的,必须启动“挑战”机制。

主流的做法有几种:

  • 滑块验证、点选验证码、文字识别验证——人工成本高,用户体感差,但拦截效果好。
  • JavaScript挑战——服务器返回一段JS,浏览器执行后生成校验结果再继续访问。正常浏览器秒过,攻击脚本一般不会完整执行JS逻辑。
  • 设备指纹收集页面——让客户端上报浏览器指纹信息,根据指纹识别是否为真实浏览器环境。

这套机制不能一直开着,用户体验会大打折扣。我的做法是做联动开关:当WAF或者监控判定当前处于攻击状态时,自动将对高风险路径的访问切换为“验证码模式”,其他路径保持正常访问;等攻击流量回落后再自动关闭。这样既能抗住攻击,又不影响九成以上的正常用户。

4.4 资源侧的兜底手段

边缘层和业务层都做了防护,但依然会有漏网之鱼进到应用内部。这时候就得在资源侧做一些兜底设计,防止单点被击穿导致整个系统雪崩。

  • 数据库连接池上限:给数据库连接池设一个硬上限,宁可让请求快速失败,也不能让它无限堆积。连接池被打满时,后面的请求直接返回“系统繁忙”,而不是无限等待,这能够保住数据库不宕机。
  • 接口级别超时:所有外部调用和数据库查询都要设置超时时间。我常用的标准是SQL查询超过3秒直接断开,HTTP调用超过5秒直接熔断。你可以根据自己业务的P99响应时间去微调,但建议别太宽松,否则攻击请求会长时间占着执行线程。
  • 热点数据缓存:把搜索、列表、详情这类查询量大的接口,尽量用Redis缓存扛住,缓存能挡住80%的重复请求穿透到数据库。比如搜索结果可以缓个30秒到1分钟,列表页可以做整页缓存。
  • 消息队列削峰:对于下单、导出这种重操作,把请求丢进消息队列异步处理,前端立即返回“已提交”。这样即使攻击流量翻了几倍,后端处理能力也还是稳定的。

资源侧的这些设计,不只是防御CC攻击有用,对应对业务突发高并发同样有效。属于投一次资、长期受益的工程优化。

5. 实战中的排查思路和避坑记录

最后分享一些实战里踩过的坑和总结出来的排查思路。这些经验花了不少代价才换来,写出来能帮大家避开一些不必要的弯路。

5.1 典型误判场景

误判分两种:一种是漏报,攻击发生了没发现;另一种是误杀,把正常用户给限流了。漏报的情况前面聊过,多看看数据库慢查询和连接数异常基本能避免。误杀的情况反而更容易犯,我举几个真实处理过的场景。

有个客户是高校的网站,全校学生共用同一个校园网出口IP,按IP做了50r/s限流后,等于半个学校的学生被挡在门外。这个问题的解法是改成语义会话限流,按Cookie匿名标识来限制每个浏览器的频率,而不是按IP一刀切。

还有一个是移动端App场景,用户的User-Agent都一样——都是某品牌手机系统内置的WebView版本,请求都走同一个域名。有人用UA特征做了拦截规则,结果把所有移动端用户全拦了。教训就是:UA这种字段可以在应用层轻易伪造,你用UA做拦截规则时一定要先统计当前真实用户的UA分布,别拿单一特征去定义攻击。

5.2 攻击绕过CDN直连源站的处理

再讲一个印象很深的案例。某客户通过CDN做了防护,攻击者一开始确实被挡在前面。但后来不知道什么渠道泄漏了源站IP,攻击直接打源站,服务瞬间崩溃。排查时我们看到CDN侧流量正常,源站侧却CPU跑满,这才意识到源站IP泄露了。

处理分几步走:

  1. 先从CDN控制台获取回源IP段列表。
  2. 在源站防火墙/安全组上配置白名单规则,只允许这些回源IP访问源站的80和443端口。
  3. 更换源站IP,同时排查IP泄露的可能渠道,比如解析记录、证书透明日志查询、代码仓库里的旧配置等等。

切记不要把源站IP写在CDN配置之外的任何地方。另外云厂商的安全组里可以顺手加一条:除了回源放行,其余来源IP全部拒绝。这个操作做完,源站IP即使被拿到,攻击也打不进来。

5.3 慢速攻击参数调优建议

慢速连接类攻击,在Nginx层面有几个关键参数可以调。默认配置下,Nginx会等待一个连接发送完整请求头,等待时间如果太长,攻击者就可以一直占用连接。推荐改成更短的值:

# 请求头超时时间,从默认的60s改短到10s client_header_timeout 10s; # 请求体超时时间,默认60s改短到10s client_body_timeout 10s; # 保持连接超时时间 keepalive_timeout 5s;

这几个参数需要结合真实业务来权衡,比如用户上传大文件时,请求体超时太短会导致上传失败。建议先统计现有业务场景下的上传耗时分布,再决定一个宽容值。我的经验是,普通业务场景下client_header_timeout设10秒够了,因为它只影响请求头接收;大文件上传场景可以给上传接口单独配置一个更宽松的client_body_timeout。

慢速攻击的识别还可以用系统状态来辅助判断。我习惯跑一条命令快速查看当前TCP连接状态分布,观测ESTABLISHED连接数和发送队列状态的变化趋势。

ss -ant | awk '{print $1}' | sort | uniq -c netstat -ant | grep ESTABLISHED | wc -l

如果ESTABLISHED连接数一直高位不降,而QPS和带宽都很低,那基本就是慢速攻击没跑了。你可以到这一步再针对连接维度做限制。

5.4 一套可复用的排查时序

真实线上排查CC攻击,最怕的是乱,东看一眼西看一眼毫无章法。我自己养成了一套固定流程,效率高很多,分享给你。

排查建议按下面的顺序来:

  1. 先看流量和连接数:用监控面板看入口带宽、QPS、活跃TCP连接数三个指标。确认是“流量型”还是“连接型”攻击。
  2. 再看业务指标:看数据库活跃连接数、缓存命中率、核心接口的响应时间。判断攻击是否已经影响到底层服务。
  3. 拉取Access Log做聚合:按URL、按IP、按User-Agent、按Referer分组统计请求量。找出请求热点。
  4. 做请求特征分析:抽样看被攻击的请求日志,分析UA是否单一、Referer是否缺失、请求参数是否规律性变化、访问路径是否有前置页面。
  5. 针对特征出临时规则:根据特征先在WAF或Nginx层上临时拦截规则——拦截恶意UA、封禁异常IP段、添加限流。
  6. 联动开启人机验证:威胁持续时,在核心接口启动验证码或JS挑战模式。
  7. 事后复盘更新基线:把攻击流量特征加入黑名单规则库,同时更新流量基线数据,方便下次更早识别。

这套流程最核心的一点是:任何规则上线前都要想好“误杀怎么办”。临时规则最好带个自动过期时间,比如封禁IP只封24小时,验证码模式设定3小时后自动关闭。别一直开着,不然攻击退了,用户也被你烦走了。

我个人在实操里的体会是,CC攻击的防御没有一劳永逸的方案,它本质是一场成本和耐心的博弈。攻击者不断地升级伪装手法,你就得不断地升级识别维度。与其寄希望于某个“神器”能一次挡住所有攻击,不如老老实实把基线、限流、缓存、超时这些基本功做好做扎实。这套地基打好了,就算哪天真被打了,你也能知道自己手里有哪些牌可以打,知道怎么一步步把系统从濒危状态拉回来。经验这个东西,攒多了,遇到事就不慌。这些坑我都替你先趟过了,照着做,大概率能少交一点学费。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询