ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

防恶意刷单实战:从规则引擎到设备指纹的三层风控体系设计

防恶意刷单实战:从规则引擎到设备指纹的三层风控体系设计

“02防止恶意刷单”,这个编号就像我们内部项目排期里的一个专项任务。我在交易平台做风控这几年,接到的第一个硬骨头就是它。当时看到这个词,以为是给运营提个醒,真正深入进去才发现,它牵扯到账号体系、设备识别、行为建模、订单处置、客服申诉一整条链路。今天这篇就把这套方案完整拆开来讲,从怎么看清单子,到怎么搭防线,再到怎么避开我踩过的那些坑,一次说清楚。适合正在做电商、外卖、小程序交易、会员体系,或者任何有下单场景的开发者、运营和风控产品经理参考。

1. 先认清对手:恶意刷单的业务链路与常见形态

防刷单的第一步,不是写代码,也不是上模型,而是把“对手”的行为拆清楚。我见过很多团队一上来就搞随机森林、图神经网络,结果样本没打标、特征没梳理,模型上线一通误杀,最后全团队都在处理客诉。刷单的本质是制造异常交易数据,但异常的类型不一样,对应的检测特征和处置手段完全不是一回事。

1.1 三种常见恶,不是所有刷单都是冲量

第一种是冲量单。商家为了搜索排名、销量权重、店铺评分,雇人批量拍下商品。这种订单的特点最明显:短时间、高频率、同类商品、多家店铺通用一套账号和设备。它伤害的是平台数据生态,让真实竞争被扭曲,消费者按销量排序买到的其实是刷出来的商品。

第二种是退款套利单。利用新用户补贴、满减券、免单活动,下单后立刻申请退款,把补贴和优惠券套出来。更狠一点的玩法是组合优惠叠加,把订单金额压到极低,然后通过赔付、运费险、延迟发货赔偿获利。这种单子和正常用户的行为差异在于:对商品本身毫无兴趣,只用最短路径完成“下单—付款—退款”,而且往往会一次性下单多个账号。

第三种是攻击性下单。同行或者恶意用户利用不付款、不发货、批量拍下占库存,让真实用户无法购买,或者故意制造大量差评和异常退款来拉低店铺评分。这种行为的特征是订单状态大量停留在“待付款”或“已取消”,退款原因高度相似,用户id之间有账号关联。

我在实际项目里发现,很多团队把三种类型混在一起做规则,结果就是“冲量单的特征”和“退款单的特征”互相冲突。比如冲量单可能是正常支付,攻击单可能不付款,用“是否付款”做单一维度判断,一定会漏掉一半。所以动手之前,先按业务模式把刷单类型分开,再分别提炼特征,这是最重要的一步。

1.2 团伙化操作的六个可识别信号

现在单打独斗的刷单已经很少了,基本都是团队化、平台化运作。我这里结合几个真实项目的观察,梳理出六个在数据上可以被锁定的信号。

设备信号。一个设备在短周期内关联了多个账号,或者多个账号共享了同一批设备标识,这是最硬的特征。正规用户一部手机通常只登录一两个账号,而刷单设备一晚上能过十几个号。这块可以用设备指纹服务,也可以自建关联关系计算。

时间信号。刷单账号通常会在凌晨或商家活动开始的几分钟内集中操作。为什么?因为半夜真实用户少,订单特征更容易被淹没;活动开始那几分钟则是因为补贴力度最大,套利效率最高。特征上表现为同一时段内订单量呈脉冲式暴涨,而真实业务通常是比较平缓的曲线。

网络信号。订单的IP归属地与收货地址长期不一致,或者IP段集中在某个机房、商业宽带。正常订外卖的人,IP位置和收货位置大概率在同一个城市;刷单团队经常用远端IP来掩盖真实身份。

收货信息信号。不同账号反复使用同一批手机号、收货地址、收件人名。就算账号不一样、设备不一样,只要最后收货信息高度复用,嫌疑立刻上升。这里要特别注意虚拟号码平台的场景,同一段号段的号码大量出现时,往往是脚本注册产生的。

浏览行为信号。真实用户下单前会花时间看详情页、看评价、比较参数,就算买得再快也要滑几下屏幕。刷单脚本为了让订单显得真实,也加了浏览动作,但它们的点击轨迹规整、停留时间均匀、几乎不滚动页面,特征上非常容易被行为埋点捕获。

支付信号。刷单订单的支付账号、支付时段、支付设备往往高度集中,或者倾向于选择某些不可追溯的支付方式。当然过度依靠支付渠道判断容易误伤,但配合其他信号使用价值很高。

这六个信号拆出来之后,下一件事才是思考怎么拦截,这也引出了整个系统的分层设计。

2. 防刷系统的三层防线:从规则到模型的设计思路

防刷系统不能只靠单一技术手段,原因很简单:每一层手段都有成本和绕过方式。规则引擎便宜直观,但容易被脚本猜透;设备指纹能力很强,但误伤面大;行为模型聪明,但依赖高质量标签和算法团队。所以我把整个防线拆成三层,逐层拦截,互相补位,这也是目前主流交易平台采用的通用思路。

2.1 第一层防线:规则引擎,用最小成本拦住大部分垃圾

规则引擎是性价比最高的起点。不需要训练数据,不需要GPU,业务同学也能看懂。核心作用是把那些毫无疑问的垃圾单在进入业务系统之前就拦下来,比如同一设备一小时下单十几次、同一IP关联几十个账号、使用已知的黑名单手机号段。

规则引擎本质上是一个评分累加器,每个特征命中就累加风险分,超过阈值就走对应处置。下面是一段我实际项目中抽出来的核心逻辑,简洁但可以说明设计思路:

def evaluate_order(order_ctx): score = 0 reasons = [] # 规则1:同设备关联账号过多,直接给重分 if order_ctx.device_account_count > 5: score += 30 reasons.append("device_account_over_5") # 规则2:同IP近1小时订单量异常高 if order_ctx.ip_order_count > 10: score += 20 reasons.append("ip_order_volume") # 规则3:几乎没浏览直接下单,非常可疑 if order_ctx.browse_pages < 2 and order_ctx.browse_to_order_seconds < 5: score += 25 reasons.append("no_browse_fast_checkout") # 规则4:收货信息近期被多个账号复用 if order_ctx.same_receiver_recent_orders > 3: score += 15 reasons.append("receiver_reused") if score >= 80: level = "block" elif score >= 60: level = "limit" elif score >= 30: level = "review" else: level = "pass" return score, reasons, level

这段代码里每个规则的权重和阈值,不是拍脑袋定的。我的习惯是先拉一周的历史样本,用分布图去看各个特征在正常订单和确认刷单订单上的区分度。区分度越大、越确定的特征权重越高,比如设备关联账号数,因为它几乎不存在误伤空间。而像“浏览时间短”这种特征,正常用户也可能有,权重就设置得低一些,只是用来加分而不是一票否决。

规则引擎的优点是好解释、方便调优,缺点也很明显:一旦规则被对手摸透,对方只要把行为改得“像人”一点,规则就失效了。所以它只能当第一层,不能当全部。

2.2 第二层防线:设备与网络指纹,识别规模化操纵

规则引擎挡不住的,是那些做了伪装、分散了频率的刷单行为。这时候要靠设备与网络指纹,把散落在不同账号下的订单重新关联起来。

设备指纹的含义,比你想象的要宽。不仅包括App端的设备ID、操作系统版本、屏幕分辨率、是不是模拟器,还包括浏览器的Canvas指纹、WebGL渲染参数、字体列表、时区语言组合。我曾经遇到过一个刷单团伙,每个账号都用了不同的手机号和IP,但所有订单都来自同一个浏览器指纹,一关联立刻穿帮。

网络层面的指纹同样关键。IP本身容易被换,但IP背后能提取的信息比IP值更稳定。比如ASN归属、使用代理、IDC机房的概率、基站位置、WiFi名称特征,这些维度相互印证,就能得到一个相对稳定的“网络指纹”。把设备和网络信息拼到一起,就可以构建一张账号关联图:哪些账号共享设备,哪些设备共享网络,哪些网络又把账号连接在一起,中间的团伙结构一目了然。

但这一层也需要谨慎。设备指纹对隐私要求比较高,收集范围要克制,而且误伤风险大,家里两个人用同一部手机登录两个账号是很正常的事。所以设备指纹的结论不要直接给“拦截”,而是作为输入,大幅拉高风险评分,然后把是否拦截的决策交给下一层或者人工审核。

2.3 第三层防线:行为序列模型,分辨真实用户与脚本

行为和设备用完了,剩下的就是那些养号很充分、设备很干净、行为刻意模仿真实用户的“精品刷单”。这种单子,单看每个维度都正常,但把整个操作序列展开,还是能看出不像人。

真实用户的行为序列有随机性。他可能先看两张图,翻到评价区,中途退出,又进来,犹豫几分钟,加购,再删掉,最后下单。整个过程的时间间隔、点击位置、滚动速度都不均匀。而刷单脚本的行为是程序化的,即使做了随机延时,分布也过于均匀,不会出现真实用户那种“卡一下”“回头看了半天”的停顿。

技术实现上,我遇到过两种主流路线:一种是把行为时间序列喂给时序模型或Transformer,做序列异常检测;另一种是把行为离散化成统计特征,比如页面停留时间的方差、点击轨迹的熵、滚动事件数量,然后用孤立森林或梯度提升机打分类。对绝大多数中小团队来说,第二种足够用,而且解释性更好。

我自己更推荐“统计特征+梯度提升机”起步。数据量小、能解释、调参不复杂,上线之后还能根据特征重要性反推哪些行为指标最有区分度,慢慢沉淀成第二层和第一层的新规则。模型输出概率可以映射成风险分,和前面的规则引擎分数加权合并,形成最终风险等级。这套多层打分的机制,比任何单一模型都稳健。

3. 从0到1落地一套防刷方案:数据、特征与处置闭环

设计说得再好,落地才是真考验。这一章我按真实项目的落地顺序,把从数据采集到最终处置的完整链路走一遍。很多人做防刷死在第一步,因为埋点没做,数据不全,后面再强的算法都是空中楼阁。

3.1 第一步先解决数据:埋点和日志必须提前规划

防刷系统依赖的数据主要有三类。第一类是注册登录数据,包括手机号、设备标识、注册时间、注册来源渠道、邀请关系。第二类是行为数据,包括页面浏览、点击、停留、滚动、加购、下单、支付等事件,前后端都要埋。第三类是业务订单数据,包括商品、金额、优惠券、收货信息、退款记录、支付渠道。

前端埋点是很多团队容易糊弄的地方。我的建议是,至少在关键页面上埋这几类事件:商品详情页加载、页面滚动深度、点击次数、停留时长、是否查看评价、加购动作、下单页填写时间。不要埋键盘输入原文,也不要采集与风控无关的隐私信息,合规红线必须守住。事件最好按会话维度聚合,一个会话里串起来的就是一条完整行为序列。

数据链路的技术选型,大厂一般会用Kafka接Flink做实时特征,落到Elasticsearch或Hive做离线分析。如果你是小团队,不需要照搬这套架构。最开始可以只做一个简单的后端日志管道,订单接口和核心行为接口在业务逻辑里同步调用一个风险评估服务,评估结果跟着订单落库。量起来了再考虑引入消息队列,异步化处理。实测下来,前三个月完全够用。

3.2 特征工程:8个高区分度特征的构建口径

有了数据,下一步就是把原始数据加工成特征。我整理了八个在实际项目中区分度最高、又容易实现的特征,口径也一并列出来,方便你对照落地。

特征名计算口径风险方向
设备关联账号数该设备近24小时内关联登录过的账号数量数值越高风险越大
同IP订单量同一IP近1小时产生的订单总量数值越高风险越大
浏览深度下单前访问的商品详情页个数小于2个时风险高
浏览到下单间隔从进入详情页到点击提交订单的秒数小于5秒且无其他页点击时风险高
收货信息复用次数相同手机号或详细地址在近7天关联的不同账号数大于3时风险高
下单时段集中度某账号/设备在近24小时内下单时段的离散程度均匀出现在整点或凌晨更可疑
退款速度下单到申请退款的时间差小于10分钟且占比高时风险高
评价文本相似度同店铺近100条评价之间的平均文本相似度相似度大于0.85时风险高

特征口径一定要定义清楚,尤其要注意时间窗口。窗口太短,正常用户的家庭共用设备也会被误伤;窗口太长,团伙把动作拉长铺开,特征就不集中。我的经验是,设备关联类用24小时窗口,IP类用1小时窗口,收货信息类用7天窗口,各管各的节奏,不要用一个固定窗口打通所有特征。

3.3 判定与处置:四级策略比“拦或不拦”更合理

防刷判定不要只输出“放行”和“拦截”两个结果。一刀切会让很多边缘用户流失,还会造成大量申诉工单。我习惯用四级处置策略,在业务效果和风控强度之间找平衡。

放行:风险分低于30,正常进入下单流程,不打扰。观察:风险分在30到60之间,订单先正常创建,但进入实时监控队列,如果同设备后续出现更多风险动作,立即升级处置。限制:风险分在60到80之间,可以下单,但限制使用大额优惠券、限制参与秒杀和补贴活动。拦截:风险分高于80,直接拒绝下单,返回提示文案并支持申诉。

这个策略在实际项目里有一个额外好处:它把风控造成的业务损失控制在可接受范围内。观察订单如果最终被确认是正常的,系统会自动沉淀为负样本反馈;真正产生资损的只有拦截那一层。分级处置让风控团队和运营团队的矛盾小很多。

3.4 反馈闭环:申诉、白名单与每周期待迭代

防刷不是一次性上线就完事。系统跑起来之后,必须建立一个反馈闭环,否则规则会不断衰减。我负责的项目里,每周会做一次这样的事:从观察队列和拦截记录里抽一批样本,交给客服团队核对,确认哪些是真实用户误伤,哪些是没识别出来的刷单。

核完的结果回流到标注表,每两周增量更新一次模型和数据阈值。同时,为低风险支付方式、老用户、内部员工账号设白名单,白名单直接跳过规则引擎。还要做一个小提醒:白名单一定要设有效期,超过90天自动失效,否则账号转手之后白名单就成了刷单者的保护伞。

4. 实战中的常见问题与排查技巧实录

所有防刷系统都会在运行中遇到“假阳性”和“假阴性”的反复拉扯。我这边踩过不少坑,也总结出一套排查方法,直接说结论,希望能帮你省点时间。

4.1 误杀激增:先看特征分布,不要急着动阈值

有一次大促活动,系统误杀率从0.3%飙到3%,客服工单爆炸。团队第一反应是调高阈值,但我拦住了。我拉出订单特征分布一看,发现触发量最大的特征不是设备关联数,而是“IP订单量”。原因是办公楼出口IP共享用户多,活动期间大家集中在同一时段下单,导致同IP订单量暴涨。

这个案例的教训是:误杀激增时,先做特征拆解,找到是哪个特征在顶阈值,再判断它是真的失效了还是业务场景变化了。贸然调阈值,要么没解决误伤,要么放过真刷单。正确做法是给特征增加业务场景维度,比如对办公IP段、学校IP段单独放宽阈值,而不是动全局参数。

4.2 规则被绕过:用动态规则和蜜罐对抗

刷单团伙也会根据系统反应做调整。我们之前用“同设备账号数”拦截了一批,结果对方改成每次清设备标识、换个新设备再上号,规则第二天就失效了。对抗这类绕过,不能靠把阈值调得更严,因为这样误伤会更大。

我的做法有两个。第一是规则随机化,同一判定结果不固定绑定同一套规则组合,让对手无法猜透具体触发条件。第二是布蜜罐。在用户下单流程里放一个正常用户永远看不见、但脚本会误触发的隐藏字段,比如某些特定id的页面节点,脚本采集数据时一旦访问到这个节点,系统立刻能锁定一批账号。蜜罐的价值不在于拦截,而在于快速识别新的刷单团伙特征。

4.3 团队没有算法能力:先做规则系统,别急着上模型

很多小团队来问我,说我们没有算法工程师,是不是防不了刷单了。真不是。我最早期的一个项目,团队连专职数仓都没有,就靠一套规则引擎加运营人工抽查,硬是把无效订单占比从7%压到了1.5%以内。

小团队起步方案:先只接订单数据和基础设备信息,把2.1节那套规则评分跑起来,每天由运营导一份高风险订单列表人工复核。运行两周后,根据复核结果给规则调权。之后如果出现漏网变多的情况,再考虑接行为埋点和现成风控SDK。记住一个原则:防刷系统的价值是降低资损和净化数据,不是炫技。规则系统能解决的问题,就没必要上大模型。

说到底,防恶意刷单是一场没有终点的攻防战。我在实际项目里体会比较深的一点是:防线不是越硬越好,而是越“稳”越好——既能挡住批量异常,又能放行绝大多数真实用户,还要能随着对手策略的变化持续调整。你现在手里的数据基础也许还不够,没关系,先搭起规则框架,补上埋点,跑通人工复核闭环,再一步步往里加设备指纹和模型。这样推进,也许不是最炫的,但一定是走得最稳的。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进