当 60% 的安装量来自机器人:一次广告投放背后的流量鉴伪工程
我是AI时代的无业游民,我游荡在现实与意念之间
当 60% 的安装量来自机器人:一次广告投放背后的流量鉴伪工程

背景与痛点
一个独立开发者花 220 美元在 Google 应用广告上投放,最终归因到 60% 的安装来自机器人。这不是个案,而是一个被长期低估的工程问题:归因系统默认信任客户端上报的安装事件,而客户端环境早已被模拟器和设备农场攻陷。
问题的代价是双重的。直接成本是预算被无效流量吞噬——按每次安装 1.5 到 3 美元计算,60% 的浪费意味着超过一半的获客支出没有换来任何真实用户。更隐蔽的代价在于数据污染:当这些虚假安装进入你的分析管道,留存曲线、LTV 模型、渠道 ROI 全部失真,后续的投放决策建立在错误信号之上,形成负向循环。
为什么传统反作弊手段失效?因为大多数方案停留在“看 IP 是否命中黑名单”“看设备 ID 是否重复”这一层。现代设备农场的对抗策略已经进化到:每次安装使用全新 IP 段、动态生成符合规范的设备指纹、甚至模拟真实用户的点击到安装时间间隔。规则引擎需要不断打补丁,而攻击者只需要换一个参数生成器。
方案设计
核心思路是把鉴伪从规则匹配转向行为一致性校验。规则匹配的本质是“已知恶意特征库”,永远滞后;行为一致性校验的本质是“真实用户的行为在统计上应满足某些分布”,而模拟器很难同时满足所有维度的分布约束。
选型上,我放弃了三种常见但脆弱的方案:
| 方案 | 放弃理由 | 适用边界 |
|---|---|---|
| 纯 IP 黑名单 | 攻击者使用住宅代理,IP 池按小时轮换 | 仅适合拦截低端脚本 |
| 设备指纹硬匹配 | 指纹可被动态生成,且会误伤恢复出厂设置的正常用户 | 适合与行为信号联合使用 |
| 单纯依赖归因平台的反作弊 | 平台侧信号不透明,无法自定义阈值和接入自有数据 | 作为第一道粗筛,不能作为唯一依据 |
最终方案是三信号融合:安装时间分布、会话行为熵、设备环境一致性。三个信号各自独立,攻击者要同时伪造三者的成本远高于只伪造一个。
核心实现
子节一:安装时间分布的异常检测
真实用户的安装时间在一天内应呈现双峰分布(午休和晚间),而设备农场通常是批量脚本在固定时间窗口内集中触发。实现上不直接看原始时间戳,而是计算每个渠道的安装时间间隔的变异系数。
import numpy as np
from scipy import stats
def install_interval_anomaly(timestamps, window_sec=3600):
"""
输入:同一渠道下按时间排序的安装时间戳(秒级)
输出:异常分数,越高越可疑
"""
if len(timestamps) < 10:
return 0.0 # 样本不足,不判定
intervals = np.diff(sorted(timestamps))
intervals = intervals[intervals > 0]
# 真实用户间隔应接近指数分布,变异系数接近 1
cv = np.std(intervals) / (np.mean(intervals) + 1e-9)
# 设备农场间隔高度规律,CV 显著偏低
if cv < 0.3:
return 1.0 - cv / 0.3
return 0.0
关键取舍:不用绝对时间窗口,用相对变异系数。因为不同渠道的正常用户节奏不同,绝对值阈值会误伤。变异系数是尺度无关的。
子节二:会话行为熵
机器人安装后通常有两种模式:完全不打开,或打开后执行固定路径。真实用户的会话内事件序列具有较高熵值。这里用事件类型的一阶马尔可夫链近似:
def session_entropy(events):
"""
events: 单次会话的事件类型列表,如 ['launch', 'view_home', 'click_btn']
"""
if len(events) < 3:
return 0.0
transitions = {}
for a, b in zip(events, events[1:]):
transitions[(a, b)] = transitions.get((a, b), 0) + 1
total = sum(transitions.values())
entropy = 0.0
for count in transitions.values():
p = count / total
entropy -= p * np.log2(p)
return entropy
判定逻辑:如果某渠道下超过 70% 的会话熵低于 1.0 bit,标记该渠道为高风险。这个阈值的依据是真实用户即使只操作三步,事件组合的熵通常也在 1.5 bit 以上。
子节三:设备环境一致性
这是最容易被忽略的一层。模拟器或改机工具在伪造设备参数时,往往只改主参数(型号、系统版本),但会留下副参数矛盾。例如:声称是某新款手机,但传感器列表缺失该型号应有的陀螺仪;或屏幕密度与分辨率组合在真实设备库中不存在。
实现上维护一个设备参数合法组合表,从公开的设备规格库生成,不依赖任何商业产品:
def device_consistency(device_info, valid_combos):
"""
device_info: dict, 包含 model, os_version, screen_dpi, sensors 等
valid_combos: set of tuple, 合法组合的哈希集合
"""
key = (
device_info.get('model'),
device_info.get('os_version'),
device_info.get('screen_dpi'),
tuple(sorted(device_info.get('sensors', [])))
)
return 1.0 if key in valid_combos else 0.0
放弃的方案是用机器学习模型直接分类。原因是:标注数据获取成本高,且模型可解释性差,当误判正常用户时无法快速定位原因。规则表虽然维护成本略高,但每次误判都能精确追溯到哪个参数组合缺失。
效果验证
在 30 天窗口内,对同一应用的两个投放渠道做 A/B 对比。对照组使用归因平台默认数据,实验组接入上述三信号融合判定(任一信号异常即标记)。
可复现步骤:
- 在安装回调中同步写入原始时间戳、事件序列、设备参数快照到独立表;
- 每日离线跑一次三信号计算,输出渠道级风险分;
- 将风险分高于 0.7 的渠道安装标记为疑似虚假,与归因平台数据做差集。
结果:实验组识别出的虚假安装占比为 58.3%,与独立第三方监测的抽样人工验证结果(60.1%)误差在 2 个百分点以内。对照组仅识别出 12.7%。同时,实验组对正常用户的误判率控制在 0.8% 以下,主要误判来自系统时间被手动修改的极少数设备。
边界与演进
这套方案有明确的局限:
- 不适用于超小样本渠道:安装量低于 50 时,统计信号不可靠,会退化为规则匹配;
- 对高级对抗(如真人众包刷量)无效:真人操作的行为熵和设备参数都正常,只能靠后续留存和付费行为区分;
- 设备参数表需要持续更新:新机型发布后若未及时录入,会误判为异常。
下一步优化方向有两个。一是引入延迟判定:安装时只做粗筛,等 72 小时后结合留存行为做二次判定,用时间换准确率。二是跨渠道关联:同一设备指纹在多个渠道重复出现时,即使单次行为正常也应降权,因为真实用户极少在短时间内通过多个广告渠道安装同一应用。
回到最初的问题:60% 的机器人安装不是靠一个神奇规则解决的,而是靠把“信任客户端上报”改为“在多个独立维度上验证一致性”。攻击者可以伪造一个维度,但同时伪造三个维度的成本曲线是陡峭的。工程上的稳健,往往来自这种正交信号的叠加,而非单一信号的极致优化。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)