我是AI时代的无业游民,我游荡在现实与意念之间


当 60% 的安装量来自机器人:一次广告投放背后的流量鉴伪工程

An abstract visualization of a vast digital ocean

背景与痛点

一个独立开发者花 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 对比。对照组使用归因平台默认数据,实验组接入上述三信号融合判定(任一信号异常即标记)。

可复现步骤:

  1. 在安装回调中同步写入原始时间戳、事件序列、设备参数快照到独立表;
  2. 每日离线跑一次三信号计算,输出渠道级风险分;
  3. 将风险分高于 0.7 的渠道安装标记为疑似虚假,与归因平台数据做差集。

结果:实验组识别出的虚假安装占比为 58.3%,与独立第三方监测的抽样人工验证结果(60.1%)误差在 2 个百分点以内。对照组仅识别出 12.7%。同时,实验组对正常用户的误判率控制在 0.8% 以下,主要误判来自系统时间被手动修改的极少数设备。

边界与演进

这套方案有明确的局限:

  • 不适用于超小样本渠道:安装量低于 50 时,统计信号不可靠,会退化为规则匹配;
  • 对高级对抗(如真人众包刷量)无效:真人操作的行为熵和设备参数都正常,只能靠后续留存和付费行为区分;
  • 设备参数表需要持续更新:新机型发布后若未及时录入,会误判为异常。

下一步优化方向有两个。一是引入延迟判定:安装时只做粗筛,等 72 小时后结合留存行为做二次判定,用时间换准确率。二是跨渠道关联:同一设备指纹在多个渠道重复出现时,即使单次行为正常也应降权,因为真实用户极少在短时间内通过多个广告渠道安装同一应用。

回到最初的问题:60% 的机器人安装不是靠一个神奇规则解决的,而是靠把“信任客户端上报”改为“在多个独立维度上验证一致性”。攻击者可以伪造一个维度,但同时伪造三个维度的成本曲线是陡峭的。工程上的稳健,往往来自这种正交信号的叠加,而非单一信号的极致优化。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐