惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
有赞技术团队
有赞技术团队
L
LangChain Blog
C
Check Point Blog
博客园 - 【当耐特】
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI
美团技术团队
博客园 - 司徒正美
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
S
SegmentFault 最新的问题
A
About on SuperTechFans
Blog — PlanetScale
Blog — PlanetScale
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗
腾讯CDC
B
Blog
G
Google Developers Blog
The Cloudflare Blog
P
Proofpoint News Feed

Aimee's Blog

防薅羊毛怎么做:号码风控、设备指纹与分层策略 接口限流怎么选:固定窗口、滑动窗口、令牌桶 批量打包下载怎么设计:流式 ZIP 与异步任务 图片处理怎么做:异步处理与 CDN 实时参数 大文件上传怎么设计:分片、断点续传、秒传 报表可重跑的设计:快照、水位线与幂等 UV 统计为什么有误差:精确计数与近似计数怎么选 大数据量导出怎么做:流式写入与异步任务 排行榜的两类需求,难度差了一个数量级 内容审核怎么选:先审后发,还是先发后审 实时热榜怎么设计:Redis ZSet 与热度分值 互关状态怎么保持同步:双向关系的维护与缓存失效 并发点赞的计数设计:原子操作与最终对账 删了父评论,子评论怎么处理——先想清楚用户看到的是什么 定时消息任务触发了两次 消息量大,写扩散还是读扩散——接到这个需求先问清楚规模 同一条消息推送了三次 活动结束了,用户还在收短信 接到注销需求,先问两个问题 微服务与服务拆分:何时拆、怎么拆 异步与事件驱动架构:把协作从「打电话」改成「发消息」 高可用设计:怎么让系统尽量不宕机 可扩展性设计:怎么让系统加机器就能扛更多 缓存架构:多级缓存怎么搭 高并发三板斧:限流、熔断、降级 架构设计到底在设计什么 —— 从单体到微服务的演进 服务成本账:一个服务一个月烧多少钱 可观测性:线上出问题怎么查 API 设计:好接口长什么样 消息队列:为什么要 MQ,以及丢失、重复、顺序怎么破
秒杀怎么防机器人:验证码之外的几道防线
Aimee · 2026-08-19 · via Aimee's Blog

秒杀怎么防机器人:验证码之外的几道防线

限量秒杀场景有个普遍现象:活动开始不到一秒就售罄,而正常用户的请求往往一两秒后才到达——抢到的大多是脚本,请求特征高度一致、时间戳精确到毫秒、操作路径和真人完全不同。

「我们有验证码」挡不住这件事:打码平台几毛钱一次,秒级识别。验证码挡得住普通人,挡不住专业团队。


机器人的优势在于速度

正常用户打开页面 → 点按钮 → 请求发出,整个链路至少 1-2 秒。

脚本:活动开始前提前拿好 Token、提前算好请求参数,时间一到立刻发出——比正常用户快 1000 毫秒以上。这 1 秒的优势,在高并发秒杀里决定了一切。

对抗机器人不是要把它们彻底赶走,而是让它们的速度优势消失


排队队列:请求先进队,不直接打数据库

秒杀请求不要直接更新库存,而是先进队列:

public SeckillResult joinQueue(long userId, long itemId) {
    // 1. 用户是否已经在队列中
    if (queueService.isInQueue(userId, itemId)) {
        return SeckillResult.duplicate();
    }
    // 2. Redis 原子判断库存
    Long remaining = redis.decr("stock:" + itemId);
    if (remaining < 0) {
        redis.incr("stock:" + itemId); // 回补
        return SeckillResult.soldOut();
    }
    // 3. 进队列,异步创建订单
    mqProducer.send(new SeckillMessage(userId, itemId));
    return SeckillResult.queuing();
}

库存在 Redis 里预减,减到 0 就拒绝后续请求(不再进队列),保护数据库不被打穿。队列里的消息由 Worker 逐条处理、创建订单,处理速度可控。


请求合法性校验

机器人通常绕过了正常的页面流程,直接构造请求打接口。用页面 Token 校验合法性:

  • 用户打开商品详情页时,服务端生成一个 pageToken(UUID,有效期 5 分钟),埋在页面里
  • 用户点击"立即购买"时,前端把 pageToken 带上
  • 后端校验 pageToken:存在且未使用过才允许下单,用过即销毁(一次性)

脚本通常不走打开详情页这一步,拿不到有效的 pageToken,请求被拦截。

对抗手段:攻击者可以爬页面拿 Token。所以还要结合:Token 的颁发频率限制(同一用户 N 秒内只给一个)+ 行为分(没有正常的浏览行为就拿 Token,评分低)。


行为分:操作速度异常

人类的点击操作有自然的时间间隔,鼠标移动有轨迹,机器人没有。

前端采集行为信号:

  • 页面停留时长(< 500ms 就点购买:异常)
  • 鼠标移动路径(直线、无轨迹:异常)
  • 按钮点击位置(每次精确在同一像素:异常)

这些信号打包成行为分上传,行为分过低时要求做人机验证(图形拖拽、算术题)。注意:用行为分触发验证,而不是所有用户都验证——减少正常用户的摩擦。


几道防线叠加

单一手段都可以被绕过,组合防御让攻击成本升高:

层次手段机器人成本
请求层接口限流(令牌桶)请求频率被压低
合法性pageToken 一次性校验必须完整走页面流程
行为行为分 + 动态验证码需要逆向前端采集逻辑
排队队列削峰,速度优势消失快 100ms 进队也没用
库存Redis 预减,DB 不被打穿数据库层有兜底

没有银弹,只有成本博弈。防御的目标不是让机器人零成功率,而是让它的攻击成本超过收益,让大多数人放弃。