CC攻击(Challenge Collapsar)中最难防御的不是每秒几千次的高频洪水,而是那种每隔几十秒发一次请求、每次只带几个连接的低频慢速攻击。传统基于QPS阈值的防护规则对这种攻击几乎失效,因为它的流量特征看起来跟正常用户没什么两样。真正有效的识别手段是计算用户行为熵值——通过量化一个访问者在时间窗口内的行为模式混乱程度,把"看起来正常但实际上在慢慢耗死服务器"的攻击者从真实用户中筛出来。这套方法的核心逻辑是:正常用户的行为有一定的随机性和多样性,而低频慢速攻击脚本的行为模式高度重复、熵值极低,两者在数学上可以被清晰区分。
什么是用户行为熵值
熵(Entropy)这个概念来自信息论,最早由香农提出,用来衡量信息的不确定性。放到网络安全场景里,用户行为熵值就是衡量一个访问者在一段时间内,其访问行为的"可预测程度"。如果一个用户的请求时间间隔、访问页面、请求参数都高度规律,那他的行为熵就很低,说明这个人大概率是脚本;如果一个用户今天访问首页、明天看详情页、后天又回来搜东西,时间间隔忽长忽短,那他的行为熵就高,大概率是真人。
具体计算方式是这样的:在一个滑动时间窗口(比如5分钟或10分钟)内,把用户的所有行为特征离散化,比如把请求间隔分成若干个区间(0-1秒、1-5秒、5-10秒……),把访问的URL路径也分成若干类别,然后统计每个特征的概率分布,代入香农熵公式 H = -Σ p(i) * log2(p(i))。最终得到一个0到某个上限之间的数值,数值越低说明行为越机械、越可预测。
为什么传统CC防护对低频慢速攻击失效
主流的CC防护策略通常依赖几个指标:单IP每秒请求数、单IP每分钟请求数、连接数峰值。这些指标对付高频攻击很管用,比如一秒几百次请求直接封掉。但低频慢速攻击故意把频率压到每分钟几次甚至十几次,完全在阈值之下。更狡猾的是,攻击者会用大量不同的IP(比如肉鸡网络)轮流发起请求,每个IP的流量都不超标,从单IP维度看根本触发不了任何规则。
这种攻击的危害在于"慢刀子割肉"。服务器处理每个请求都要消耗资源,尤其是涉及数据库查询、动态页面渲染的请求。攻击者不需要打垮带宽,只需要让服务器一直处于"半忙"状态,正常用户进来就排队、超时、体验极差。而且因为流量小,很多防护设备的日志采样都可能漏掉它。
行为熵值计算的具体实现步骤
第一步,数据采集。需要在Web服务器或反向代理层(比如Nginx、OpenResty)记录每个访问者的关键行为字段,包括:时间戳(精确到毫秒)、请求URL、请求方法(GET/POST)、User-Agent、来源Referer、Cookie或Session ID、响应状态码。这些数据可以通过访问日志实时写入消息队列(如Kafka),再流入计算引擎。
第二步,特征提取与离散化。以时间间隔为例,假设我们观察10分钟窗口内某用户的所有请求,得到一组时间间隔值:[3.2s, 2.8s, 3.1s, 3.0s, 2.9s, 3.3s]。这些值高度集中在3秒附近,离散化后几乎全部落入"2-5秒"这个区间,概率接近1,熵值趋近于0。而正常用户可能是:[0.5s, 45s, 120s, 3s, 8s, 200s],分布在多个区间,熵值明显更高。
第三步,多维熵值融合。单一维度的熵值可能有误判,比如某个用户就是习惯每隔3秒刷新一次页面(比如在看直播数据)。所以需要把多个行为维度的熵值做加权融合,常见的维度包括:时间间隔熵、URL路径熵、参数分布熵、请求方法熵。最终综合熵值 = w1*H_time + w2*H_url + w3*H_param + w4*H_method,权重可以通过历史数据训练得到。
第四步,设定动态阈值并触发动作。不是所有低熵用户都是攻击者,需要设定一个自适应阈值。可以用无监督学习(比如孤立森林、DBSCAN聚类)对历史正常用户的熵值分布建模,找出正常用户熵值的下界。当某用户的综合熵值持续低于这个下界超过一定时间(比如连续3个窗口),就标记为可疑,触发限速、验证码挑战或直接阻断。
核心算法的伪代码实现
# 用户行为熵值计算核心逻辑(Python伪代码)
import math
from collections import Counter
def calculate_entropy(values, num_bins=10):
"""计算单个维度的熵值"""
if len(values) < 2:
return 0
min_val, max_val = min(values), max(values)
if min_val == max_val:
return 0
bin_width = (max_val - min_val) / num_bins
bins = [0] * num_bins
for v in values:
idx = min(int((v - min_val) / bin_width), num_bins - 1)
bins[idx] += 1
total = len(values)
entropy = 0
for count in bins:
if count > 0:
p = count / total
entropy -= p * math.log2(p)
return entropy
def multi_dim_entropy(user_sessions, weights=[0.4, 0.3, 0.2, 0.1]):
"""多维熵值融合"""
h_time = calculate_entropy(user_sessions['intervals'])
h_url = calculate_entropy(user_sessions['url_categories'])
h_param = calculate_entropy(user_sessions['param_hashes'])
h_method = calculate_entropy(user_sessions['method_codes'])
return (weights[0]*h_time + weights[1]*h_url +
weights[2]*h_param + weights[3]*h_method)
def detect_low_slow_cc(user_id, window_sessions, threshold=1.5):
"""判断是否为低频慢速CC攻击"""
entropy = multi_dim_entropy(window_sessions)
if entropy < threshold:
return True, entropy # 可疑
return False, entropy
滑动窗口与实时计算架构
行为熵值计算对实时性要求很高,不能等攻击打完了再分析。推荐采用滑动窗口架构:以1分钟为粒度,每30秒滑动一次,每个窗口独立计算。技术栈上可以用Flink或Spark Streaming做实时流计算,Redis存储每个用户最近N个窗口的中间状态,避免重复计算。对于高并发场景(比如每秒十万级请求),需要对用户ID做分片,每个分片独立计算,最后汇总。
需要注意的是,窗口大小的选择直接影响检测效果。窗口太小(比如1分钟),正常用户的行为样本不够,熵值计算不稳定;窗口太大(比如30分钟),攻击已经造成了损害才被发现。实践中建议用多尺度窗口并行计算——同时跑1分钟、5分钟、10分钟三个窗口,取最敏感的那个做判断。同时设置"冷却期",如果用户被标记后行为恢复正常(熵值回升),自动解除标记,避免误伤。
与其他防护手段的协同配合
行为熵值计算不是万能的,它最好作为CC防护体系中的一个智能检测层,和其他手段配合使用。比如:第一层用传统的频率限制做粗筛,挡住明显的高频攻击;第二层用行为熵值做精筛,识别低频慢速攻击;第三层用人机验证(JavaScript挑战、滑块验证码)做最终确认。对于被熵值系统标记为低熵但又不想直接封的用户,可以先弹一个无感验证(比如在页面里嵌入一段JS,正常浏览器会执行,脚本不会),通过了就放行。
另外,行为熵值还可以和IP信誉库联动。如果一个IP的历史行为熵值长期偏低,即使当前没有触发阈值,也可以提前降低该IP的信任等级,在后续请求中施加更严格的限速。这种"行为画像+实时检测"的组合,比单纯看单次请求特征要可靠得多。
实际部署中的常见坑和优化建议
第一个坑是冷启动问题。新用户没有历史行为数据,熵值计算可能不准。解决办法是给新用户一个较宽的容忍阈值,或者用群体行为做参考——比如新用户的行为模式和已知正常用户群体的平均熵值对比,而不是和绝对阈值比。
第二个坑是攻击者的对抗。聪明的攻击者会在脚本里加入随机延时(比如在2-5秒之间随机),试图抬高熵值。对此,需要提高采样精度,不只是看间隔的分布,还要看间隔序列的自相关性——真正的随机和伪随机在高阶统计特征上是有区别的。可以引入二阶熵或条件熵来检测这种对抗。
第三个坑是性能开销。每个请求都要更新用户状态、计算熵值,对服务器是额外负担。建议做异步处理:请求进来先快速判断是否命中简单规则(比如频率超限),没命中的再异步送入熵值计算管道,结果写回Redis供下一次请求读取。这样不会阻塞主请求链路。
效果评估与持续迭代
部署行为熵值检测后,需要持续监控几个核心指标:误报率(正常用户被误判的比例)、漏报率(攻击没被识别的比例)、检测延迟(从攻击开始到被标记的时间)。建议每周做一次回溯分析,把被标记的用户样本拉出来人工审核,确认是否真的是攻击。根据审核结果调整阈值和权重,形成闭环优化。长期来看,这套系统会越用越准,因为积累的数据越多,正常用户的行为模型就越精确。
总结来说,用行为熵值识别低频慢速CC攻击,本质上是从"流量大小"的粗放防御升级到"行为模式"的精准防御。它不依赖单一指标,而是从多个维度综合判断一个访问者的"人性程度"。这套方法虽然实现复杂度比传统规则高,但在面对日益精细化的攻击手段时,它是目前性价比最高的技术路线之一。
