趣头条安全团队简介:负责趣头条所有业务线业务安全和基础安全,自主研发设备指纹、实时风控、风险识别等反作弊系统,以及WAF、漏洞平台、白盒扫描等基础安全平台,负责公司合规安全、网络安全、系统安全、数据安全和业务安全等。
趣头条App自发布以来,一直受到黑产和散户的不断攻击,反作弊在与黑产一次次对抗中,逐渐吸取经验教训,形成了符合自己业务特色的反作弊技术体系。本文将从实用性角度简要介绍一下趣头条反作弊的技术架构和SDK部分细节。
反作弊SDK
为什么要开发反作弊SDK?
第一,与业务解耦。很多公司的反作弊,是没有自己收集数据的,依赖业务数据来做分析,这样固然也能做反作弊,但业务数据量大,设备信息不全,用户行为繁多,数据格式无法统一,更有甚者,业务字段的变化可能完全不会通知反作弊团队,会导致策略失效。有了独立于业务的反作弊SDK后,不仅数据格式统一了,新增功能发版也更自由了,策略可控易维护。
第二,获取真实可信的设备环境。业务数据一般会直接调用系统接口取设备环境参数,但这些参数非常容易被Hook篡改,有大量专门的改机工具可以修改系统参数,所以要保护好系统参数,就要识别出这层修改,或绕过,或用其他办法来获取真实可信的设备环境数据,这就需要有独立的专业SDK。
第三,设备指纹。有了自己的SDK,就可以做唯一的设备识别了。在移动领域,不限于移动安全,设备指纹有着极其重要的地位,不仅用于反作弊,还用于业务数据统计和产品策略制定(如单一设备只能参加一次活动),还用于广告投放,渠道拉新等等。
很庆幸,我们一开始就走对了方向,坚持开发自己的反作弊SDK,经过数轮迭代,目前已经非常稳定,内部数十个App已经接入反作弊SDK,也就是说每出一个新App,首先需要接入的就是反作弊SDK。
在SDK防护方面,我们也做了相当多的工作,在保证兼容性的前提下,尽可能做到安全,提高被破解的门槛和风险。
首先,我们自定义了一套数据编码格式,即非JSON,也非Protobuf,兼顾了安全和编码效率,编码后的数据再经过压缩,变成更加紧凑的二进制。
其次,我们设计了自己的加密算法和签名算法,并用C实现,且做了混淆和加固。抓包拿到的报文,经过编码压缩加密后,是二进制,企图通过猜测碰撞的办法来破解加密算法,几乎是不可能的。
然后,核心参数,我们会在C层也获取一次,并和Java层相互校验,如果缺失C层参数或C层和Java层不匹配,那么就有理由怀疑用户使用了改机软件或非真实设备。
最后,我们会检测调试,调试状态下返回的报文和正常报文有差异。
当然SDK防护不限于此,总之,在多个点上安插我们的防护代码,加强SDK自身安全,提高门槛,并且做到风险可感知。
反作弊SDK完成了两项重要任务:
- 结合服务端算法生成设备指纹和tuid(下文有详细介绍),依靠SDK对客户端环境很强的感知能力,加上强大的服务端算法,设备指纹的可以达到很高的准确度。
- 上报客户端环境参数,我们采集的参数偏向于显性的,例如开机时间、音量、光感等等,是符合国家安全合规要求的,部分参数只有在用户同意的情况下,才会获取,而且单次回话中不会大量重复获取,依靠这些看似不起眼的参数,我们可以做很多策略来识别虚假设备,例如模拟器、越狱、参数聚集等等。
以模拟器为例,通过校验各种参数,我们开发了30多种识别模拟器的策略,严谨而准确。众所周知的,模拟器一般的CPU架构不是 ARM,而是 Intel 或 x86,通过这一特征,可以大幅缩小模拟器的识别范围,但有些手机CPU架构确实是x86,所以要结合其他参数来辅助判断。市面上大多模拟器,都有自己的一些特征,某些参数无法修改,或者一般用户不知道怎么修改,那么可以通过这些特征轻而易举地识别出这类模拟器,例如蓝叠模拟器的Wifi名字可能就叫BlueStacks。大多数模拟器,都有自己独特文件或进程特征,这些不易被篡改,识别准确度也很高,例如雷电模拟器进程中含有 com.android.emu.coreservice。还有些云真机默认的品牌和硬件参数,会暴露它的身份,如品牌为 Redfinger、CloudPhone 可能是红手指云手机、华为云手机,但这些参数可以轻易修改,这就需要其他策略来识别了。
设备指纹
唯一标记一台真实设备,在用户正常操作后,如重装App、重启设备、重装系统、备份还原等,能确保设备指纹不发生变化。注意,设备指纹不是银蛋,不是万能的,所以这里说的是真实设备、正常操作。对于虚假设备,我们只有策略或模型识别出假设备就可以了,不必保证设备指纹唯一。恶意用户异常操作也是一样,识别处理即可,无需在设备指纹算法上浪费太多精力,即便能保证唯一,意义也不大,回报率极低。当然,并不是说,只要用户稍微篡改一下设备参数,我们设备指纹就放弃抵抗了,这里有一个平衡,避免花大量时间和精力做强对抗,如果低成本能保证篡改后设备指纹依然唯一,那最好了,我们现在就能保证大多数情况下参数被篡改后设备指纹依然不变。
我们的设备指纹经过了多次算法尝试和技术的演进,每个版本都迭代了数十次。
第一版,单字段映射。
最初开始设备指纹的算法研究与实现时,Android 生态一片繁荣,设备参数如IMEI还基本可用,黑产也没有到疯狂的地步。我们的算法主要是以单字段映射为主,也就是ID Mapping。这个算法的好处是简单,容易理解,容易实现,遇到问题,也能轻易地排查找到原因。数据全部放在Redis中,做了高可用,并实时备份,以防Redis意外,数据不会丢,并能快速恢复。开始上线时,效果非常好,准确率高。期间,做过一次大迁移,通过数据双写,服务从一个云迁移到另一个云,数据没有一条丢失和错误,这得益于合理的方案和周密的计划。但这套系统用了不长时间,很快问题出现了。业务爆发式的增长,我们的设备指纹服务,设备量很快过亿了,由于ID类型一直在不停地增加,加一个,就是加一亿的数据,最终Redis Key 达到十多亿,一再扩容,但成本也急剧上升,再估算一下未来的业务增长趋势,成本将无法控制。同时另一个问题,也显现出来,随着设备的增多,单字段的冲突问题逐渐暴露出来了,多个设备被识别成一个,这也是完全不能接受的。
第二版,多字段映射。
在第一版中,冲突的问题,是绕不过的,于是,我们又重新思考了,最终决定,采用多字段映射,在解决冲突的前提下,依然能够保持简单。但Redis成本问题,已经无法胜任了。调研了一些数据库,没有找到合适的数据库,在各种权衡下,还是使用了MySQL,一张表建了10多个索引,就这样,在已知有风险的情况下,依然跑了起来。这个版本使用了很长时间,系统稳定,设备指纹准确率也提升了很多,在快速增长的业务需求下,依然保持了较高的可信度,误差很小。
但该来的问题还是来了,在一个安静清明节早上凌晨4点,系统报警了,MySQL CPU 过高。难以想象在系统低峰期,CPU 居然过高?后证实下来,是云服务共享导致的,立即切换了独享版。
平静了两个月后,系统再次报警了,这次是周六早上,排查下来,是DB超时错误。日志中的 SQL 重跑一遍后,很快发现了问题,居然有子查询返回上万条数据,是意料之外的。于是立即做了降级处理,最多返回100条。问题得到暂时的缓解。深入排查后,发现是设备参数的默认值导致的,上万设备某个参数都是一样的,于是对这些默认值做了特别处理后,系统又恢复正常。
但从这次事故中,我们还是感觉到MySQL的风险,数据量大,索引即将超过限制,没有扩展的余地,MySQL 毕竟是关系型数据库,不适合 KV 场景。于是,我们又花了大量时间,重新调研适合我们场景的数据库,尤其是 KV。在经过数月的评测研讨,最终有了结论,尝试一个新的数据库 Aerospike。
经过了漫长的数据迁移和对比实验,Aerospike终于被证实是可靠的而且适合我们场景的数据库。至此,DB问题终于被解决了。
第三版,基于自主优化的模型算法。
Android 生态接二连三地发生重大变化,尤其是IMEI 被禁用,OAID作为替代方案,还有国家安全合规要求,不能过多过早获取用户设备信息。虽然我们并不依赖某些设备参数,但隐私政策收紧的趋势已经很明显,必须提前做好准备。于是我们又开始计划新的设备指纹算法,形式不同往日,当前挑战比以往更大。复杂的问题允许相对复杂的解决方案,我们新的算法相对前面版本已经不再简单了,而是一个可以自主优化的算法,可以随时调整模型,能让后来生成的设备指纹越来越准。经过数月的对比实验,不仅证明了新算法的可行性,而且证明了新算法有天然的优势,准确率高于前一版本。
设备指纹是个细致活,通过一次次的优化,一个个的细节问题被发现被解决,踩过的坑都成为了我们光辉的历史,指导我们一步步把设备指纹做得更准确更稳定。
tuid
曾经,tuid是个极富争议的话题,外部环境不可控,并非所有人都能理解,所以不同的部门认知不同,对这个ID有不同的要求,要满足所有的要求,是不可能的,需要在平衡各种需求的情况下,尽力提升ID的准确性实时性。
tuid 是什么?tuid是 服务端设备指纹(即上文讲到的设备指纹)和客户端临时指纹的组合提取。新设备或App重装后,服务端设备指纹需要一次网络返回,在网络返回前,业务数据已经开始上报了,这时就需要一个ID来对应到这个设备,并且能和服务端设备指纹关联上。在设计设备指纹时,我们就预先考虑到这个情况,所以让客户端临时指纹和服务端设备指纹有很强的关系。这样,经过一定的算法和匹配,就能够从两个指纹中提取出一个共同的ID来,这就是 tuid。
首次提出tuid,是在AB实验中,由于IMEI冲突、改码、用户不给权限等等,造成通过IMEI等设备参数无法进行实验分流,得出的数据非常不置信。数据中心找到我们,希望能够提供一个相对稳定的ID用于实验平台。由于对实时性要求较高,单纯服务端设备指纹也满足不了要求,于是我们提出可以试一下客户端临时指纹+服务端设备指纹的方案,从两者当中提取出共同的 tuid,作为实验分流ID。实验平台经过尝试后,发现效果非常好。自此便开启了 tuid 的时代,但也只是单一平台小规模运用。
然而,IMEI等设备参数不可靠的问题,在业务线越来越严重,对比tuid或其他平台,108万的新增,使用IMEI作为口径,可以统计出127万新增,误差接近20%,同时各业务线不同部门数据更是难以对齐。在 ONE ID ONE DATA ONE SERVICE 的号召下,各部门尤其是数仓,迫切需要一个相对靠谱的ID来打通并对齐底层数据。
在对比了各个ID后,包括 QID、Android ID、UUID、tuid、IMEI、其他第三方ID,发现并不存在一个理想的ID,能满足所有场景,尤其是Android 环境不断变化的情形下,无法预知某个ID在未来几年的表现。但可以确定的是,在明确App打开前几秒,ID 可能不准的前提下,最接近理想的 ID 是 tuid,于是会议决定使用 tuid 作为 打通并对齐底层数据 的唯一ID。于是,tuid正式登上舞台。全业务线,所有数据体系大规模改造,全部使用 tuid。
随着数仓系统的改造,各种数据也逐渐对齐,指标也趋于稳定,IMEI 混乱的时代终于可以结束了,有了 tuid,数据第一次被算清楚了,这使所有部门看到了数据的准确,看到了数据的整齐,决策也有了信心。
但事情并没有那么顺利,在由谁计算新增的问题上,反作弊和数据中心的意见产生了分歧。反作弊提供了的 tuid 方案,而且有自己的设备指纹系统,已经实时标记了新增。但数仓的要求是,新增必须走数据中心来计算。走反作弊,优点是方案和实现统一在反作弊形成闭环,有现成的系统,缺点是有少量设备可能只在业务线上报,不在反作弊库中,新增会少。数据中心计算新增,优点是数据中心自己负责重要数据的产生和计算,自己负责高可用,不依赖其他系统,缺点是设备参数可能发生变化,在App打开前几秒,客户端临时指纹有一定概率和服务端设备指纹不一致,导致生成两个tuid,计算两次新增,也就是说实时数据产生了假新增,新增会多,但离线可以排除,日活影响不大。
各方沟通下来,最终还是确定了数据中心来计算新增。这就需要一套方案来消除或降低假新增比例。离线能够识别假新增,是因为反作弊同时上报了客户端临时指纹和服务端设备指纹,可以做映射。所以我们上线了一套tuid转换服务,解决实时数据有假新增的问题。这个方案成本很大,需要所有使用tuid的服务都做一次tuid转换的改造,部分业务线在网关层做了转换,后面的微服务就不需要转换了。这个转换过程99.9%是本地的,只有不到0.1%需要远程。假新增就在这0.1%中,转换后,实时的假新增比例控制在1-2%,这个值是稳定的,而且离线可以排除干净。
tuid改造完成之后,实时指标也越来越准确越来越稳定。
但自Android 8以后,Android 系统接二连三地发生了重大变化。首先 Android ID 不再是唯一的,同一设备对不同的App会返回不同的 Android ID。然后 Mac 地址随机,接着禁止获取序列号等等,其他参数也受到系统管制和权限的限制。好在我们的设备指纹系统不强依赖于这些参数,所以基本没受到任何影响。客户端临时指纹的稳定性虽受到挑战,但得益于tuid转换服务,tuid的依然能够保持相对稳定。
然而,随后而来的隐私合规和国家出台的一系列个人信息保护政策,对我们tuid冲击很大。我们获取的环境参数都是在合规范围内的,也不会获取敏感的用户个人信息,例如电话本、短信等等,所以这些要求,对我们没有影响。影响大的是,要在用户同意隐私协议之后才能获取环境参数,这对我们一向主张的实时性要求相冲突。我们要求反作弊SDK要尽早初始化,尽快拿到服务端设备指纹。但隐私协议的规定让我们不得不延迟初始化,这样带来了更多的设备没有拿到服务端设备指纹,而只能拿到客户端临时指纹,所以造成了假新增暴涨,最高达到18%,这是不可接受的。
必须有一套方案能够解决Android系统变化问题和反作弊SDK初始化较晚的问题,而且要低成本。理想情况是,客户端有个准确的不需要权限可以随用随取的不会变化的设备ID。但这只能个空想,过去不可能,现在国家安全的要求和Android系统的发展趋势都不允许有这样的ID来跟踪用户行为。
其实通过日常数据监控,我们已经发现客户端临时的设备指纹稳定性在缓慢变差,需要增强,tuid转换服务过于简单,数据不丰富。再进一步分析数据,发现假新增可以由其他环境参数,通过模型来修正,可修正比例高达 80%以上,再加上多种策略,大幅降低假新增比例,是完全可能,而且是确定可实现的。成本呢,我们已有的tuid转换服务,为我们搭好了架构,铺好了路,只要稍做调整即可。于是客户端临时指纹增强版,加上服务端tuid转换服务优化,方案定下来了。由于改造不太,实现很快落地了,效果和预估的一样,指标变化非常显著,加上网关层全面推进tuid转换,假新增从18%重回 1-2%。
回想一下,当初确定tuid转换方案的时候,确实遇到不少阻力,好在有领导层的支持,有大家的坚持,最终全面铺开了。现在看来,这个架构抗风险性很强。如果没有这个tuid转换服务,很难想象,隐私合规和Android系统的变化带来的挑战,我们如何才能应对。这个问题即便放到现在,也没有一套方案能够做得更好,我们没有,市面上也没有,甚至很少有公司考虑过实现客户端设备指纹的事情,虽然这是刚需。
tuid 的困难在于外部环境不可控。从小的方面讲,设备的碎片化可能导致任何意想不到的问题,从大的方面讲,国家政策,Android 系统重大更新,都是无法预测的。
tuid转换服务,就在客户端和服务端做了一个缓冲的桥梁,缩小甚至消除外界变化带来巨大影响。后续大环境发生变化,我们依然可以通过这个缓冲调整模型来应对。
上述从三方面介绍了反作弊SDK相关的技术和变革,反作弊SDK解决了反作弊遇到的挑战,同时也满足了业务苛刻的需求。对比业界优秀的设备指纹服务,我们的设备指纹达到了极高的准确率,双方的准确率均接近99.99%,在个别设备识别上各有千秋。独创的tuid方案,在业界首次解决了实时数据统计分析无可靠口径的难题。
趣头条反作弊从零开始,把一个个服务建立并完善,在真实的场景中磨炼,得到反馈,总结经验,吸取教训,沉淀出了一套完整的闭环的反作弊体系,已经成为中台核心组成部分。黑产技术在不断更新,反作弊技术也需要持续创新,并且要提前防御,尽可能避免与黑产持续强对抗。
E N D
目前,已有外部公司与我们合作,帮助他们解决黑产问题和业务上的数据问题,他们能够享受与我们内部业务无差别的服务,使用我们完整的反作弊技术,例如实时风控、风险识别、算法模型等等。如果您或您的公司在业务中遇到了困难或黑产攻击,可以联系我们, 我们愿意提供技术交流和服务试用。联系邮箱 ifsall@qutoutiao.net。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。