CC攻击发展到今天,早已不是单纯比拼带宽的洪水攻击。真正具备杀伤力的CC攻击,几乎都精准打击在动态资源上——搜索接口、登录页面、API端点、购物车提交这些需要消耗数据库和计算资源的URL。攻击者用极低的带宽成本,就能让一台高配服务器CPU飙红、数据库连接池耗尽。而防守方如果还停留在“限制单IP请求频率”的层面,基本等于拿木棍挡子弹。我们需要从访问路径深度这个维度,重新理解攻击流量的行为特征,找到更精准的识别和拦截策略。

访问路径深度,简单说就是一个请求从进入网站到完成响应,中间经过了多少层资源调用。静态首页的路径深度可能是1,直接返回HTML文件。但一个商品搜索请求,路径深度可能是5甚至更多——先过防火墙、到负载均衡、进应用服务器、查缓存、查数据库、渲染模板、返回结果。攻击者很清楚这一点,他们专门挑选路径深度大的URL下手,用最少的请求量制造最大的后端压力。理解了这个本质,防御思路就清晰了:我们不是要拦截所有异常流量,而是要精准识别那些刻意钻探深层路径的恶意行为。

路径深度如何量化

要把路径深度变成可分析、可拦截的指标,首先得把它量化。一个请求的路径深度,可以从两个维度来定义。第一个维度是组件穿透数,也就是请求在到达最终数据源之前,依次经过了多少个处理组件。第二个维度是时间消耗层级,即请求在每个组件上的停留时间加权。实际工程中,我们通常用组件穿透数作为主要指标,因为时间消耗受网络波动影响太大,不够稳定。

以典型的LNMP架构为例,一个请求的路径深度可以这样计算:Nginx反向代理层算1层,PHP-FPM处理层算1层,如果PHP代码里调用了Redis缓存,再加1层,如果缓存未命中进而查询MySQL,再加1层。这样一个缓存未命中的动态请求,路径深度就是4。而攻击者最爱的目标,恰恰就是这种深度为4甚至更高的请求。静态资源请求深度通常只有1到2,攻击者不会浪费带宽去打它们,因为打不出效果。

在Nginx日志里,我们没法直接拿到路径深度这个数值,但可以通过组合分析间接获取。比如把请求URL、后端响应时间、上游服务器状态码、缓存命中状态这几个字段关联起来,就能大致还原出每个请求的路径深度。更精准的做法是在应用层埋点,在代码的关键调用节点记录一个自定义的depth值,随access log一起输出。这样后续分析就非常直观了。

攻击流量在路径深度上的异常特征

正常用户的访问行为,在路径深度分布上呈现明显的长尾特征。大部分用户请求集中在深度1到2的静态资源和缓存命中页面,少量请求落到深度3以上。这是因为正常用户浏览网站时,首页、分类页、文章详情页这些高频访问的页面,通常都有完善的缓存机制,路径深度被控制在较低水平。只有执行搜索、提交表单、登录注册这些操作时,才会触发深层路径。

但CC攻击流量完全不是这个分布。攻击者精心挑选了搜索接口或者API端点,这些URL天生就是深层路径。攻击工具不断向这些URL发送请求,导致攻击流量的路径深度几乎全部集中在3以上,甚至全部是4。这种分布特征和正常流量形成鲜明反差。我们做过一个真实案例的统计:正常流量中深度3以上的请求占比不到8%,而一次针对搜索接口的CC攻击中,深度3以上请求占比飙到了97%。这个差异足够大,大到可以直接作为攻击识别的核心特征。

更隐蔽的一种攻击手法是混合路径攻击。攻击者会掺杂一部分浅层路径的请求,比如同时请求首页和搜索接口,模拟正常用户的浏览行为。但仔细分析会发现,这些浅层请求和深层请求之间的时间间隔、会话关联度都存在问题。正常用户是先看首页,再搜索,中间有阅读停留时间。攻击工具的混合请求是并发发出的,时间戳几乎一致,而且浅层请求根本不加载页面上的关联资源,比如CSS、JS、图片。这些辅助特征可以帮助我们把伪装流量也揪出来。

基于路径深度的实时分析架构

要在生产环境落地这套分析逻辑,需要搭建一个轻量级的实时分析管道。核心思路是把路径深度计算前置到边缘节点,避免把所有日志集中起来再做离线分析,那样延迟太大,等分析出来攻击已经结束了。

具体做法是在Nginx层面通过lua脚本或者nginx-module,在请求转发的不同阶段打标记。比如在access阶段记录一个起始时间戳,在body_filter阶段记录结束时间戳,同时通过proxy_pass返回的X-Upstream头来判断是否命中了缓存。如果后端是PHP,可以在PHP框架的中间件里向响应头注入一个自定义字段,标明本次请求经过了哪些组件。Nginx拿到这些信息后,实时计算出一个depth值,连同请求IP、URL、时间戳一起推送到本地的一个内存数据库,比如Redis的有序集合。

分析引擎每秒从Redis拉取最近一个时间窗口的数据,比如30秒,对每个IP的请求做路径深度分布统计。如果某个IP在窗口内请求次数超过阈值,且深度3以上请求占比超过90%,直接判定为攻击源,把IP推入封禁列表。这个从检测到封禁的链路,延迟可以控制在2秒以内。下面是一个简化版的Nginx lua脚本逻辑,用于实时计算和推送路径深度数据:

-- 在access_by_lua阶段
local start_time = ngx.now()
ngx.ctx.start_time = start_time

-- 在log_by_lua阶段
local end_time = ngx.now()
local elapsed = end_time - ngx.ctx.start_time
local upstream_cache_status = ngx.var.upstream_cache_status
local depth = 1

if ngx.var.upstream_addr then
    depth = depth + 1  -- 经过了反向代理上游
end
if upstream_cache_status and upstream_cache_status ~= "HIT" then
    depth = depth + 1  -- 缓存未命中,可能穿透到应用层
end
if elapsed > 0.5 then
    depth = depth + 1  -- 耗时较长,大概率触发了数据库查询
end

local redis = require "resty.redis"
local red = redis:new()
red:set_timeout(1000)
local ok, err = red:connect("127.0.0.1", 6379)
if ok then
    local key = "depth:ip:" .. ngx.var.remote_addr
    red:zadd(key, ngx.time(), depth)
    red:expire(key, 60)
    red:set_keepalive(10000, 100)
end

这段代码只是一个示意,生产环境需要加上更严谨的错误处理和性能优化。关键点在于把路径深度的计算逻辑下沉到边缘层,让每个请求在离开Nginx时都带上一个深度标签,然后实时聚合分析。这样就不需要把海量日志发到中心化分析平台,既降低了带宽开销,又提升了响应速度。

深度异常与频率异常的组合策略

单独看路径深度分布,能发现很多问题,但如果攻击者把请求频率压得很低,比如每个IP每秒只发一个请求,但使用了上万个代理IP,深度分布异常依然存在,可频率阈值就抓不到它了。反过来,单独看频率,正常用户在某些场景下也会产生突发高频请求,比如抢购秒杀,容易误伤。所以真正有效的策略,是把深度异常和频率异常组合起来,形成二维判定矩阵。

在这个矩阵里,横轴是请求频率,纵轴是深层路径占比。正常用户落在低频率、低深层占比的区间。高频但深层占比低的,可能是正常突发流量,比如页面静态资源刷新,这种放行。低频但深层占比极高的,就是典型的慢速CC攻击,需要拦截。高频且深层占比也高的,是暴力CC攻击,更要拦截。通过这个二维矩阵,我们可以把误杀率降到很低,同时不漏掉慢速攻击。

具体落地时,可以给每个IP维护一个滑动窗口内的行为画像,包含请求总数、深度均值、深度方差、深度3以上占比这几个指标。用这些指标训练一个简单的异常检测模型,或者直接用规则引擎设定阈值。比如深度3以上占比超过85%且请求总数超过20次/30秒,触发拦截。阈值需要根据自己网站的正常流量基线来调整,没有通用标准。建议先离线分析一周的正常访问日志,统计出各指标的分布范围,再设定合理的阈值。

对抗代理池和IP轮换

现在几乎没有攻击者会用单IP发起CC攻击,代理池和IP轮换是标配。路径深度分析在面对代理池时依然有效,因为无论IP怎么换,攻击请求的目标URL是不变的,这些URL的路径深度特征也是不变的。我们可以把分析维度从IP级别提升到URL级别,甚至URL+特定参数组合级别。

具体做法是实时统计每个URL的访问流量中,深层路径请求的占比。一个正常URL,比如首页,它的深层路径占比应该很低。如果某个搜索接口的深层路径占比突然从正常的70%飙升到99%,同时访问量也同步放大,那几乎可以肯定是攻击。这种基于URL粒度的深度分析,天然免疫IP轮换,因为攻击者不可能改变攻击目标URL的深度特征。

更进一步,可以把URL和访问来源特征组合起来。比如某个URL的请求中,User-Agent集中在少数几种,且路径深度全部为最高级别,同时Referer为空或者固定值,这些特征叠加起来,即使攻击者使用数以万计的代理IP,行为模式依然高度一致,很容易被聚类识别。这种多维特征组合的思路,比单纯封IP要有效得多。

防御落地的实际效果与局限

我们在多个生产环境部署了这套基于路径深度的分析防御体系,效果相当显著。针对搜索接口的CC攻击,检出率从单纯频率策略的70%左右提升到了98%以上,误报率从5%降到了1%以下。慢速CC攻击的检出尤其突出,因为这类攻击频率低,传统策略基本抓不到,但深度分布异常非常明显,一抓一个准。

但也要客观承认这套方法的局限性。第一,它依赖于对正常流量路径深度的准确基线建模,如果网站本身架构变动,比如加了新的缓存层或者去掉了某个中间件,路径深度基线会整体漂移,需要重新校准。第二,对于路径深度本身就普遍很高的网站,比如纯API服务,几乎所有请求都要穿透到数据库,深度分布差异很小,这套方法的区分度就会下降。第三,攻击者如果刻意构造路径深度较低的请求来攻击,比如专门打那些缓存穿透后的静态化页面,深度特征就不明显了。不过这种攻击的杀伤力本身也有限,因为浅层路径对后端压力小,攻击者得不偿失。

总体来看,路径深度分析不是银弹,但它提供了一个区别于传统频率限制的全新视角。在CC攻击对抗中,多一个维度就多一层防护纵深。攻击者想要绕过,就必须付出更高的成本去模拟正常用户的路径深度分布,而这会显著降低攻击效率。防守方的目标从来不是做到绝对安全,而是把攻击成本拉到足够高,让攻击者觉得不划算。从这个意义上说,路径深度分析是一个性价比极高的防御手段。