沿着用户线索追查攻击:用有状态分析识别账号滥用

2026-10-02 29 预计阅读时间: 1 分钟
来源: blog.cloudflare.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

账号攻击正在从“同一个 IP 连续尝试密码”变成分布式、低频率、会主动调整行为的自动化流程。攻击者可以借助 AI 生成更像真人的请求,轮换 IP、设备指纹和请求节奏,从而绕过只检查单次请求的无状态安全规则。

Cloudflare 的 Account Abuse Protection dashboard 提供了另一种调查视角:通过有状态分析,把多个看似无关的请求串成一条行为链,并使用边缘生成的 Hashed User ID(哈希用户标识)追踪针对同一账号的活动。重点不再只是“这个请求可不可疑”,而是“这个账号在一段时间内经历了什么”。

为什么逐请求判断越来越不够用

传统规则通常观察单个请求或很短的时间窗口,例如:

  • 某个 IP 在一分钟内提交了多少次登录请求;
  • User-Agent 是否异常;
  • 请求是否来自已知代理网络;
  • 单次请求的 Bot 分数是否低于阈值。

这些信号仍然有价值,但攻击者可以把一次集中攻击拆散:使用数百个出口 IP,每个 IP 只请求一两次;模拟正常浏览器头部;在失败后改变账号、密码字典和等待时间。单独查看每个请求时,它们可能都没有越过封禁阈值。

有状态分析改变了聚合维度。安全团队可以围绕账号而不是 IP 建立时间线,回答更接近事件本质的问题:

  • 同一账号是否在短时间内被大量不同网络尝试登录?
  • 登录失败之后,是否紧接着出现密码重置、MFA 挑战或令牌刷新?
  • 多个看似正常的请求,是否共同指向同一个用户标识?
  • 攻击是否在更换 IP 后继续沿用相同的业务目标?

IP、设备和会话都可能变化,账号目标往往更稳定。Hashed User ID 就是用来连接这些离散事件的“线”。

Hashed User ID 的价值与边界

边缘生成的哈希用户标识可以让安全系统在不直接使用明文邮箱、用户名等信息的情况下,对同一用户的请求进行关联。调查人员随后可以按该标识查看登录、注册、密码重置或其他敏感流程中的连续行为。

这里需要区分“哈希化”和“匿名化”。哈希标识通常仍属于可关联的假名数据,并不天然等于匿名数据。实施时应注意:

  • 不要直接对邮箱做普通 SHA-256。邮箱空间可枚举,攻击者可以预先计算常见地址的哈希;
  • 更适合使用带服务端密钥的 HMAC,让外部人员无法离线建立明文映射表;
  • 优先选择稳定的内部账号 ID,而不是可能改变、存在别名或大小写问题的邮箱;
  • 多租户系统应把租户 ID 纳入输入,避免不同租户中的相同用户名碰撞;
  • 不应把完整哈希返回给浏览器,也不能信任客户端自己提交的用户标识;
  • 密钥轮换会改变标识,需要预先设计调查窗口和迁移策略。

Hashed User ID 适合做关联键,但不能单独作为封禁依据。共享账号、企业出口网络、密码管理器重试以及用户误操作,都可能形成类似自动化攻击的行为。

可以这样实践:在边缘生成稳定的 HMAC 标识

下面是一个可改造的 Cloudflare Worker 示例。它不是 Account Abuse Protection dashboard 的官方配置,也不代表产品内部的具体算法;它演示的是同一种工程模式:在边缘读取登录标识、生成带密钥的 HMAC,并覆盖转发给源站的内部请求头。

运行前需要把 app.example.com 改为不会再次命中同一 Worker 路由的源站域名,并根据实际登录 JSON 字段调整 email。

export default {
  async fetch(request, env) {
    const incomingUrl = new URL(request.url);
    const headers = new Headers(request.headers);

    // 永远不信任客户端传入的关联标识。
    headers.delete('X-Hashed-User-ID');

    if (request.method === 'POST' && incomingUrl.pathname === '/login') {
      let payload;
      try {
        payload = await request.clone().json();
      } catch {
        return new Response('Invalid JSON', { status: 400 });
      }

      const loginName = String(payload.email ?? '')
        .trim()
        .toLowerCase();

      if (loginName) {
        const hashedUserId = await hmacHex(env.HUID_SECRET, loginName);
        headers.set('X-Hashed-User-ID', hashedUserId);
      }
    }

    const upstreamUrl = new URL(request.url);
    upstreamUrl.protocol = 'https:';
    upstreamUrl.hostname = env.ORIGIN_HOST;

    const hasBody = request.method !== 'GET' && request.method !== 'HEAD';
    const upstreamRequest = new Request(upstreamUrl.toString(), {
      method: request.method,
      headers,
      body: hasBody ? request.body : undefined,
      redirect: 'manual'
    });

    return fetch(upstreamRequest);
  }
};

async function hmacHex(secret, value) {
  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey(
    'raw',
    encoder.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['sign']
  );

  const signature = await crypto.subtle.sign(
    'HMAC',
    key,
    encoder.encode(value)
  );

  return [...new Uint8Array(signature)]
    .map(byte => byte.toString(16).padStart(2, '0'))
    .join('');
}

可以用下面的最小配置部署。将日期更新为部署时使用的 Workers compatibility date:

name = 'account-abuse-edge-id'
main = 'src/index.js'
compatibility_date = '2025-01-01'

[vars]
ORIGIN_HOST = 'app.example.com'

密钥不要写入代码或普通变量,使用 secret 管理:

npx wrangler secret put HUID_SECRET
npx wrangler deploy

生产环境还应补充三个约束:源站只接受来自可信边缘的该请求头;日志系统限制对标识的访问和保留时间;在用户成功认证后,尽快改用稳定的内部账号 ID,而不是长期依赖邮箱规范化结果。

从 dashboard 中沿线调查,而不是看到峰值就封禁

面对登录失败峰值,可以采用下面的调查顺序:

  1. 按 Hashed User ID 聚合事件,确认攻击集中在少量账号,还是横向扫描大量账号。
  2. 展开目标账号的时间线,比较登录失败、成功登录、MFA、密码重置和会话刷新之间的顺序。
  3. 再叠加 IP、ASN、地理位置、设备和请求特征,判断攻击者是否在主动轮换基础设施。
  4. 检查成功结果。大量失败值得关注,但“失败之后突然成功”通常更需要立即响应。
  5. 根据置信度分层处置:限速、交互式挑战、临时冻结敏感操作、撤销会话,或要求重新验证身份。

不要把一个 HUID 的异常直接扩展成整个 IP 段的永久封禁。企业 NAT、移动网络和代理服务会让大量正常用户共享网络特征。更稳妥的策略是把账号维度、网络维度、行为序列和认证结果组合起来。

上线前的检查清单

  • 明确需要保护的流程:登录、注册、找回密码、优惠领取还是支付操作;
  • 为同一业务主体选择稳定且规范化的标识;
  • 使用 HMAC 或平台提供的边缘哈希能力,不记录不必要的明文身份数据;
  • 丢弃客户端伪造的关联头,只允许边缘重新生成;
  • 先观察基线和误报,再启用自动阻断;
  • 为客服、安全和隐私团队建立 HUID 到内部事件的受控调查流程;
  • 给密钥轮换、数据保留和跨区域合规留出设计空间。

有状态分析不是对 WAF、Bot 管理或速率限制的替代,而是补上它们缺少的时间与身份上下文。真正有效的账号保护,应当既能拦住当前请求,也能沿着同一账号留下的线索,看清分布式攻击的完整过程。


相关推荐