3. 登录Velocity的度量
在识别暴力破解与撞库攻击时,单看“失败次数”远远不够。攻击者可以用极慢的速度绕过阈值,也可以在短时间内爆发式尝试。要准确刻画登录行为的“速度感”,我们需要引入一组可计算的Velocity指标:时间窗口、频率、速率、加速度。它们共同回答一个问题——单位时间内,登录尝试的密度和变化趋势是否异常。
一、核心原理:从计数到速度的四个层次
Velocity度量的本质是把离散的登录事件映射到时间轴上,再提取统计特征。四个指标层层递进:
- 时间窗口(Time Window):定义观察的时间范围,如60秒、5分钟、1小时。窗口决定了“多快算快”的基准。
- 频率(Frequency):窗口内事件发生的总次数,是最基础的计数指标。
- 速率(Rate):频率除以窗口时长,得到单位时间的事件密度,如“每分钟失败次数”。
- 加速度(Acceleration):速率的变化率,即当前速率相对于上一窗口速率的增量,用于捕捉“突然加速”的攻击行为。
关键公式:
频率 F = 窗口内事件数 N
速率 R = N / T(T为窗口时长,单位秒或分钟)
加速度 A = (R当前 - R上一窗口) / T窗口间隔
这四个指标不是孤立的。时间窗口是分母,频率是分子,速率是归一化结果,加速度则引入了时间序列的对比。只有组合使用,才能同时覆盖“低频慢速”和“高频爆发”两类攻击。
二、方法流程:滑动窗口与指标计算
实际工程中,最常用的计算方式是滑动时间窗口。与固定窗口(如每5分钟清零)相比,滑动窗口能避免“窗口边界攻击”——攻击者在窗口切换瞬间集中尝试。流程如下:
- 事件采集:从登录日志中提取每条记录,字段至少包含:时间戳、用户名、源IP、登录结果(成功/失败)。
- 窗口定义:选择窗口长度T和滑动步长S。例如T=60秒,S=10秒,表示每10秒计算一次过去60秒的指标。
- 分组维度:按源IP、用户名或IP+用户名组合分组,分别计算。不同维度对应不同攻击场景。
- 频率统计:对每个分组,统计窗口内失败登录次数N。
- 速率计算:R = N / T。若T=60秒,N=30,则R=0.5次/秒,即30次/分钟。
- 加速度计算:保存上一窗口的速率Rprev,当前加速度A = (R - Rprev) / S。
- 阈值判定:根据业务基线设定阈值,如R>10次/分钟或A>5次/分钟²触发告警。
下面是一个简化的Python伪代码,展示滑动窗口内频率、速率和加速度的计算逻辑:
from collections import deque
import time
class VelocityTracker:
def __init__(self, window_sec=60, step_sec=10):
self.window = window_sec
self.step = step_sec
self.events = deque() # 存储(时间戳, 结果)
self.prev_rate = 0.0
self.last_calc = time.time()
def add_event(self, ts, success):
self.events.append((ts, success))
self._evict(ts)
def _evict(self, now):
while self.events and now - self.events[0][0] > self.window:
self.events.popleft()
def compute(self, now):
if now - self.last_calc < self.step:
return None
self._evict(now)
fail_count = sum(1 for _, s in self.events if not s)
rate = fail_count / self.window # 次/秒
accel = (rate - self.prev_rate) / self.step
self.prev_rate = rate
self.last_calc = now
return {"frequency": fail_count, "rate": rate, "acceleration": accel}
该实现中,window_sec和step_sec是核心参数。窗口越长,越能捕捉慢速攻击;步长越短,加速度越灵敏,但计算开销也越大。
三、案例场景:三种攻击的Velocity特征
假设我们监控某电商登录接口,窗口T=60秒,步长S=10秒。以下三种场景的指标表现截然不同:
| 场景 | 频率(次/分) | 速率(次/秒) | 加速度(次/秒²) | 特征解读 |
|---|---|---|---|---|
| 正常用户 | 1~3 | 0.02~0.05 | 接近0 | 低频稳定,无突变 |
| 慢速撞库 | 5~8 | 0.08~0.13 | 0.001~0.003 | 频率略高但加速度平缓,易漏报 |
| 暴力破解爆发 | 120~300 | 2~5 | 0.1~0.5 | 频率和加速度同时飙升,易触发告警 |
从表中可见,慢速撞库的频率可能只比正常用户高2~3倍,但加速度极低,单纯依赖频率阈值容易漏报。此时应结合长时间窗口(如1小时)的累计频率,或引入用户名分散度辅助判断。而暴力破解的加速度特征非常明显,适合用短窗口+加速度阈值快速响应。
实战建议:对同一IP,同时维护短窗口(60秒)和长窗口(3600秒)两套指标。短窗口抓爆发,长窗口抓慢速。两者任一超阈值即告警,可显著降低漏报和误报。
四、误区与复盘:计算Velocity时容易踩的坑
即使公式正确,工程实现中仍有几个常见误区:
- 误区一:固定窗口代替滑动窗口。固定窗口在边界处会丢失连续性,攻击者只需在窗口切换时暂停几秒即可绕过。务必使用滑动窗口或至少重叠窗口。
- 误区二:忽略成功登录。撞库攻击中,攻击者可能用少量成功登录掩盖大量失败。Velocity应同时统计失败和成功,或计算“失败/成功比”的速率。
- 误区三:加速度分母错误。加速度是速率的变化除以时间间隔,不是除以窗口长度。若用窗口长度做分母,会严重低估加速度。
- 误区四:所有用户共用阈值。不同业务线的正常登录频率差异巨大。应按业务线或用户角色分别建立基线,再设定动态阈值。
- 误区五:只按IP聚合。攻击者使用代理池时,单IP频率不高,但按“用户名”或“IP段”聚合后速率会暴露。多维度聚合是必要的。
复盘要点:每次告警后,回看该时间段的频率、速率、加速度曲线。如果加速度在告警前已经持续上升,说明阈值可以提前;如果加速度始终平缓但频率缓慢累积,说明需要补充长窗口指标。Velocity度量不是一次配置就一劳永逸,而是需要根据误报和漏报持续调参。
总结来说,时间窗口定义了观察尺度,频率提供了绝对数量,速率实现了跨窗口可比,加速度捕捉了趋势突变。四者结合,才能把“登录太快”这个模糊感觉,转化为可计算、可告警、可复盘的工程指标。