某做健康品类CPA的五人小团队,2026年3月接了一个欧洲市场的Offer,按常规做法用八个Business Manager分散投放Facebook。前四天很平静,单BM日耗在120到400美元之间,CTR稳定在1.8%上下。第五天凌晨三点,三个BM同时收到"Your ad account has been disabled",政策标注是Circumventing Systems。
团队当时的判断是素材踩线,连夜把落地页首屏文案和视频前三秒全换了一轮。第六天又倒了三个。第七天剩下两个进入受限状态,提示变成"Your Business Manager is restricted from advertising"。
复盘会开了四个多小时,素材假设头一个被推翻——八个BM实际用的是四套完全独立的素材,其中两套是从别的Offer搬过来的老素材,此前连续跑了三个月没出过任何问题。真正咬合在一起的是另外三条线。
· 八个Pixel的ID各不相同,但全部部署在同一个GTM容器里,容器ID一致,事件命名规则一致,连事件去重键event_id的生成逻辑都是同一段代码复制出来的。
· 支付绑的是三张同一家虚拟卡服务商发行的卡,BIN前六位完全相同,账单地址填的是同一个转运仓,只改了门牌号数字。
· 浏览器环境跑在同一台Windows工作站上,开了八个独立配置;代理买的是同一家机房的静态住宅,IP的C段还是连号的。
任何一条单独拎出来,都不足以让平台立刻下手。三条叠在一起,形成的就是一个高置信度的同源判定。这件事之后我找了两位做广告平台风控外包的朋友求证,他们的口径基本一致:关联判定早就不是规则引擎跑一串if-else了,而是把这些信号当成图里的边,算连通分量、算边权重、算子图相似度。你封掉一个节点,平台顺着边把整片子图都标记出来,这才是"相继受限"而不是"同时受限"的原因。
环境层做得再干净,也救不了账户层和支付层留下的强关联边。工具提供的是环境层安全,不提供行为层和账户结构层的豁免。
广告平台看的不是单点信号,是一张图
账户层:BM、广告账户、主页、Pixel之间的共享边
这一层的边是平台自己记录的,权重也居于高位,因为不存在采集误差。一个人名下的BM互相添加过管理员、两个广告账户共用过一个主页、两个Pixel被同一个GTM容器加载过、同一个Catalog被挂到过不同BM——这些都是显式的、写在数据库里的关联。很多团队做隔离时把精力全砸在浏览器上,却在后台随手做了一次"添加合作伙伴",等于亲手连了一条分量很重的边。
Pixel这块在联盟场景里格外容易翻车。CPA投放通常要把转化事件回传给广告平台,如果用的是同一套Server-Side Tracking服务,回传请求的源IP、User-Agent、事件时间戳的抖动分布、甚至action_source字段的取值习惯,都会呈现出高度一致的模式。平台不需要知道你是谁,只需要知道这批Pixel"像是同一只手在喂数据"。
支付层:BIN、账单地址、收款主体
支付信息的关联强度仅次于账户层,而且几乎不可否认。同BIN不一定被判同源,但同BIN加同账单地址加同一批卡号连号,基本就是实锤。PayPal那边更直接,同一个收款主体下挂的多个商户账号,风控是打通的。
这层的处理成本很高,是很多小团队的真实瓶颈。我见过的相对稳妥的做法是接受"账户数量上限由支付资源决定"这个现实,而不是反过来,先规划一百个账户再去凑支付方式。
环境层:设备指纹、出口IP、Cookie与本地存储
这一层才是指纹浏览器真正覆盖的范围,也是技术上可控程度较高的一层。可控意味着两件事:做好了不加分,做砸了直接扣分。平台不会因为你的Canvas噪声自然就给你放行,但会因为八个环境的AudioContext哈希完全一致而给你打标。
Cookie隔离是老生常谈,真正容易漏的是IndexedDB、Service Worker注册表、以及浏览器的HSTS超集缓存。HSTS这条尤其阴——它是按域名记录的持久化状态,即使清了Cookie也留着,可以被用来做跨会话的探测。
行为层:登录时序、操作节奏、素材复用
行为层的信号采集有误差,所以单独用它下判定的置信度不高,但它非常适合做"确认"。八个账户每天早上九点零几分整齐登录、每次充值都是同一个金额、创建广告组的字段填写顺序一模一样、上传素材的文件名里都带着同一个批次编号——这些不构成封禁理由,但会让一个已经被怀疑的子图变成确定的子图。
层级 |
典型信号 |
采集侧 |
关联强度 |
可控性 |
账户层 |
BM/主页/Pixel共享边 |
平台服务端 |
很高 |
中 |
支付层 |
卡BIN/账单地址/收款主体 |
平台服务端 |
高 |
低到中 |
环境层 |
指纹/出口IP/本地存储 |
客户端脚本 |
中到高 |
高 |
行为层 |
登录时序/操作节奏 |
双侧混合 |
中 |
低 |
内容层 |
素材哈希/落地页相似度 |
平台服务端 |
中 |
中 |
表1 关联信号按采集侧与可控性分层,可控性较高的环境层并不是权重较高的层
联盟营销独有的那条链路:Affiliate Link到Tracker到Lander到Offer
电商卖家的环境问题在浏览器里就结束了。联盟营销不是,联盟营销的身份泄露点有一半在浏览器外面,散落在跳转链路的每一跳上。这条链路通常长这样:广告位点击,进Tracker(Voluum、Binom、RedTrack这类),Tracker按规则分流,进Lander,Lander上的CTA再跳到Offer页,广告主那边回传Postback给Tracker,Tracker再回传CAPI给广告平台。
四到六跳,每一跳都是一次身份暴露机会。
Referrer:一跳漏一次
默认的referrer-policy在同源和跨源HTTPS之间会带完整URL或者至少带origin。这意味着Tracker能看到你的广告位来源,Lander能看到你的Tracker域名,Offer页能看到你的Lander域名。广告主和联盟平台顺着Referrer就能把你所有的Lander域名归到一起。
处理方式不复杂:在Lander的HTML头部显式声明策略,跳转时用中间页做一次剥离。
Referrer-Policy写成no-referrer或者strict-origin-when-cross-origin,取决于你的Tracker是否需要来源做归因。全剥了会影响归因准确率,这是个取舍,不存在两全的答案。
UTM与Sub ID的指纹化
这是被严重低估的一条。很多人的Sub ID是自己拼的,格式类似s1=fb_camp_0317_creative_b_geo_de。这串东西会原样出现在URL里、出现在Tracker日志里、出现在广告主的后台里。你的命名习惯本身就是指纹——下划线分隔、日期用MMDD、地区用两位小写国家码,这些习惯在十个不同的"独立"账户上完全一致,等于签了名。
合理的做法是Sub ID只传随机短串,真实语义在Tracker侧做服务端映射。查报表的时候多一次join,换来的是链路上不再携带可识别的结构化信息。
Tracker域名的WHOIS、DNS与证书SAN关联
域名侧的关联是公开可查的,也就是说不需要平台有任何内部数据,任何人都能查。四条主要的边:同一注册商同一批次注册(创建时间戳往往精确到分钟都相同)、同一组NS记录、同一张证书的SAN列表里出现多个域名、以及被动DNS库里解析到同一个IP或同一个C段。
证书SAN这条很容易中招。如果你图省事,用一张通配符证书或者一张多域名证书覆盖了八个Lander域名,那么crt.sh上一查,八个域名的关系一览无余,连时间线都清清楚楚。
Cloudflare同账户下多域名的关联风险
把多个域名放进同一个Cloudflare账户,会产生几个可观测的共性:相同的NS记录对(比如都是某两个固定的cloudflare.com二级域)、相同的Cloudflare边缘IP段、相同的响应头组合(cf-ray的colo字段、server头的版本、以及是否开启了某些可选特性)。加上被动DNS的历史记录,域名之间的时间相关性会非常明显。
这一层的成本是实打实的:拆账户意味着拆账单、拆API Token、拆自动化脚本。做到什么程度取决于你的Offer单价和账户重置成本,不是所有人都需要做到彻底隔离。
跳转节点 |
泄露载体 |
可被谁观测 |
处置方向 |
广告点击到Tracker |
完整Referrer URL |
Tracker与中间CDN |
声明referrer策略 |
Tracker内部302 |
Sub ID结构化命名 |
任意抓包方 |
改随机串加服务端映射 |
Lander静态资源 |
同CDN账号的域名共性 |
被动DNS与证书库 |
分账号分证书托管 |
Lander到Offer |
UTM参数组合习惯 |
广告主与联盟平台 |
参数精简到必要项 |
域名注册与解析 |
WHOIS批次/NS/SAN |
任何公开查询者 |
错峰注册分散解析 |
Postback与CAPI回传 |
源IP与时间戳分布 |
广告平台服务端 |
分散回传出口 |
表2 追踪链路上的六类泄露点,浏览器只能覆盖其中一到两项
Cloaking的边界
Cloaking,也就是对审核方和真实用户返回不同内容,属于Facebook、Google Ads明令禁止的行为,对应的政策条目就是开篇案例里那个Circumventing Systems。本文不讨论任何此类手法的实现,也不讨论如何识别审核流量。同样,联盟生态里长期存在的Cookie填充(Cookie Stuffing)——在用户未产生真实点击的情况下写入联盟Cookie窃取佣金——是各大联盟平台重点打击的作弊行为,CJ、Impact、ShareASale都有专门的检测机制和封停条款,2015年eBay联盟那起知名案件甚至进入了刑事程序。能讨论的是合规的A/B分流和地域定向,这两件事在技术实现上和违规Cloaking确实有部分重叠,区别在于三点:分流的两个版本内容实质等价、分流规则不以识别审核方为目的、以及所有版本都能通过同样的审核标准。
合规实现上有两条路径。服务端302分流的优点是首屏快、不依赖JS,缺点是Tracker必须扛住全量流量,而且302链路本身会被记录。客户端JS分流的优点是CDN可缓存、成本低,缺点是首屏会有闪烁,而且爬虫拿到的是分流前的HTML。
地域定向建议放在CDN边缘做,用边缘节点的地理判定字段而不是自己查IP库——自建IP库的更新滞后会导致同一个IP在你这里判德国、在广告平台那里判荷兰,这种不一致本身就是个信号。
指纹自洽性:平台校验的是矛盾,不是数值
这里有个特别常见的误解——以为指纹的数值越"稀有"越危险,所以拼命往大众值上靠。实际检测逻辑不是这样。平台打头的一道校验是自洽性:你声称的身份和你表现出的行为是否互相矛盾。一个稀有但自洽的指纹,风险远低于一个大众但矛盾的指纹。
UA与Client Hints的交叉验证
Chrome 89之后引入了User-Agent Client Hints,navigator.userAgentData可以拿到高熵值。问题是很多环境改了UA字符串却没同步改UACH,或者反过来。这就出现了UA写着Windows NT 10.0、hints.platformVersion却报出一个Windows 11才有的版本号(13.0.0以上)这种低级矛盾。
Canvas、WebGL Renderer、屏幕参数与字体列表
这四项要一起看,因为它们描述的是同一台设备的不同侧面。常见的矛盾包括:UA声称macOS但WebGL的UNMASKED_RENDERER_WEBGL返回了带NVIDIA字样的字符串;屏幕分辨率报1920乘1080但devicePixelRatio是2.5;声称是Windows环境但字体枚举里缺Segoe UI这类系统内置字体,或者反过来多出了只有macOS才有的字体。
字体这块补充一句,Chrome从某个版本起对本地字体访问做了收紧,纯JS的字体枚举精度在下降,检测方转向了用字体渲染差异做间接推断。所以字体列表现在的权重比两年前低了,但没归零。
TLS的JA3/JA4与HTTP/2帧序
这是浏览器改不动的一层,也是不少工具的实际短板。JA3和它的继任者JA4指纹取自TLS ClientHello里的密码套件顺序、扩展列表顺序、椭圆曲线组等字段的哈希。HTTP/2这边则是SETTINGS帧的参数顺序、WINDOW_UPDATE的初始值、以及HEADERS帧里伪头字段的排列。
真实Chrome的这些值是有明确特征的。如果你的自动化脚本走的是Node的原生fetch或者Python的requests,握手层面立刻就穿帮了——UA可以写成Chrome 137,但JA4会告诉对方这是一个非浏览器客户端。基于Chromium内核改造的工具在这一层天然占优,因为握手是内核自己发的;而那些用外部代理转发、或者在浏览器外面另起HTTP客户端的方案,很容易出现"页面里是Chrome、接口请求不是Chrome"的割裂。
校验项 |
典型矛盾表现 |
检出层 |
UA与Client Hints |
UA与hints平台不一致 |
JS层 |
WebGL Renderer |
声明Mac却报NVIDIA显卡 |
JS层 |
屏幕与DPR |
1920x1080配DPR等于2.5 |
JS层 |
字体枚举 |
Windows环境缺系统内置字体 |
JS层 |
AudioContext |
多环境哈希完全相同 |
JS层 |
时区与地理位置 |
IP在德国时区报Asia上海 |
JS层加服务端 |
TLS JA3/JA4 |
声明Chrome但握手像Node |
网络层 |
HTTP/2帧序 |
SETTINGS顺序非Chrome默认 |
网络层 |
表3 自洽性校验清单,网络层两项无法靠JS注入解决,只能依赖内核层实现
Tracker域名关联度自查:把公开信息先自己查一遍
既然WHOIS、被动DNS、证书透明日志都是公开的,那就没有理由不自己先查。下面这段Python是我们内部自查脚本的简化版,去掉了鉴权和缓存逻辑,保留判定思路。它不做任何攻击性操作,全部走公开查询接口。阈值设成3是经验值,没有理论依据。实际用下来,得分5以上的域名对基本都需要拆,3到4分的看Offer价值决定。有一点要提醒:crt.sh的返回在高峰期经常超时,脚本里那个20秒的timeout不够用,生产环境建议加重试和本地缓存。
自动化接入:环境、代理、CDP端点的绑定顺序
联盟场景的自动化通常不复杂,主要是批量查报表、批量改预算、批量拉素材数据。真正需要注意的是启动顺序——很多人的脚本是先启动浏览器再设代理,中间有几秒钟走的是本机出口,这几秒足够触发一次真实IP的DNS查询。
正确顺序是:先通过本地接口更新环境的代理配置,确认生效后再启动环境,拿到CDP端点,再用Playwright或Puppeteer接管已有实例,而不是让Playwright自己launch一个浏览器。像MostLogin这类在v2.0之后开放了本地REST API的客户端,配合CDP做接管是比较标准的路子;接管的好处是内核层的指纹配置由客户端自己维护,自动化框架只负责操作,不参与指纹注入,避免两边打架。
结尾那个随机间隔不是装饰。串行加抖动,和八个环境同时并发登录,在行为层留下的痕迹完全是两回事。
工具能力适配:联盟场景要的和电商场景不一样
电商多店铺主要看环境隔离和团队权限,联盟营销额外需要三样东西:稳定的自动化接口(因为要频繁拉Tracker和平台的数据做对账)、对移动端环境的支持(不少Offer只有移动流量,桌面环境根本跑不出转化)、以及能扛住高频切换的启动性能。
下面这张表只列技术维度,价格和商业条款不在这一节讨论范围内。
工具 |
自动化接入方式 |
移动端环境形态 |
联盟场景侧重 |
MostLogin |
CDP与本地REST API |
ARM卡板云手机 |
桌面与移动端环境统一管理 |
Dolphin Anty |
本地API与Selenium |
暂无 |
明确定位联盟营销专家 |
Multilogin |
官方API与Puppeteer |
暂无 |
内置代理,公开测试数据可查 |
Octo Browser |
本地API |
暂无 |
启动速度与内核层指纹改造 |
AdsPower |
本地API与无代码RPA |
云手机 |
电商与流程编排 |
GoLogin |
官方API,跨平台覆盖广 |
暂无 |
云端运行与内容侧生态 |
表4 技术维度适配对照,暂无移动端能力不等于不适合联盟场景,取决于Offer的流量结构
关于Dolphin Anty这个"联盟营销专家"的定位,我觉得需要客观说明:它不是营销话术,而是它的产品形态确实是围绕联盟场景做的——独联体地区的联盟社区是它的主要用户群,配置文件的批量管理、Facebook和TikTok账户的标签体系、以及和几家主流Tracker的字段对齐,都比通用型工具做得细。它的短板同样明显:目前没有移动端环境,且2022年发生过一起数据泄露事件(据公开报道波及约15%用户群),这在选型时需要一并纳入考量。
移动端这块要多说一句技术差异。市面上"云手机"至少有三种实现:x86模拟器套Android镜像、ARM服务器上跑容器化Android、以及远端ARM物理卡板独立运行完整Android系统。前两种在传感器数据、IMEI层级的还原度、以及GPU渲染特征上都有可识别的差异;物理卡板方案(MostLogin的云手机走的是这条路,同时开放ADB和ROOT)成本更高,但硬件参数的一致性更接近真机。选哪种,取决于你的Offer是否会被广告平台的移动端SDK做设备完整性校验。
代理不是越贵越好,是要匹配投放节奏
联盟投放的代理需求和电商完全不同。电商是长期稳定持有,联盟是频繁开新、频繁弃号、频繁换地区。用长租静态住宅去跑一个可能三天就死的测试账户,成本结构是错的。
代理类型 |
适配场景 |
稳定性 |
成本参考 |
主要风险 |
静态住宅ISP |
长期主账户与BM |
高 |
3至8美元每IP每月 |
同批次C段连号 |
动态住宅 |
落地页调研与竞品分析 |
中 |
4至12美元每GB |
出口频繁变化 |
移动4G与5G |
高敏感新账户冷启动 |
中高 |
15至40美元每端口 |
共享出口拥挤 |
机房数据中心 |
内部看板与对账脚本 |
高 |
1至3美元每IP每月 |
ASN易被打标 |
原生家宽独享 |
高价值长周期账户 |
高 |
20至60美元每月 |
供给稀缺周期长 |
表5 成本区间为2026年上半年公开报价的大致范围,实际价格随地区与采购量浮动较大
有一条实践经验值得单独拎出来:不要在同一个账户的生命周期里换代理类型。新号用移动代理冷启动、跑起来之后换静态住宅省钱,这个操作看起来很聪明,实际上制造了一次剧烈的环境跳变。要省,就从一开始选定一种扛到底。
新账户启用前的环境验收清单
这套清单我们跑了大概一年半,从起初的六项加到现在的十三项,删过三项(都是被证明没有区分度的检测)。它不保证任何结果,只是把可以提前发现的低级错误提前发现掉。
验收项 |
判定标准 |
验证方式 |
出口IP地理 |
与环境时区和语言一致 |
ipinfo或ip-api返回 |
DNS泄露 |
解析出口与代理同ASN |
dnsleaktest多轮 |
WebRTC |
不暴露本机内网与公网地址 |
browserleaks的WebRTC页 |
UA与Client Hints |
代码1无issue输出 |
本地自查脚本 |
Canvas与WebGL |
各环境哈希互不相同 |
创宇或browserleaks |
AudioContext |
各环境哈希互不相同 |
同上 |
字体列表 |
与声明的操作系统匹配 |
字体枚举检测页 |
时区与语言 |
语言列表与出口地一致 |
JS读取核对 |
TLS指纹 |
JA4呈现浏览器特征 |
tls.peet.ws或ja3er |
HTTP2帧序 |
SETTINGS顺序为Chrome默认 |
同上 |
本地存储残留 |
Cookie与IndexedDB为空 |
开发者工具Application页 |
插件与扩展 |
各环境扩展列表不完全一致 |
扩展管理页核对 |
时钟偏移 |
与代理所在地NTP偏差小于2秒 |
服务端时间戳比对 |
表6 十三项验收清单,全部通过只代表没有低级错误,不代表账户安全
清单里很容易被忽略的是末尾那一项。系统时钟偏差在跨时区投放时会引发很奇怪的问题——不是被判定风险,而是广告平台的排期功能会出现偏移,导致你的投放时段和竞价策略对不上,进而在行为层留下异常模式。
账户异常时的归因排查决策树
出问题的时候切忌同时改五个变量。下面这套是文字化的决策树,按顺序走,每一步只验证一个假设。
起手一步,判断异常的范围。
· 只有一个账户异常,其余正常,走分支A(个体问题)。
· 两个以上账户在72小时内相继异常,走分支B(关联问题)。
· 全部账户同时异常,走分支C(基础设施问题)。
分支A继续往下。检查该账户的支付方式是否近期变更过、是否有过一次异常的预算跳变(比如日预算从50直接改到800)、素材是否命中了品类政策。这三项都排除之后,再看环境层:单独用一个干净环境登录该账户,若能正常操作,说明是账户侧的软限制,走申诉;若立刻二次触发,说明账户已被硬标记,环境层改动没有意义。
分支B是特别需要冷静的一支。先把这批账户的共同点列出来——共同的Pixel容器、共同的支付BIN、共同的代理C段、共同的Lander域名、共同的登录时间窗。列完之后按表1的关联强度排序,从强到弱逐项拆。这里的经验是:不要先动环境层,因为环境层是可控性较高、但权重偏低的层,先动它往往浪费时间。
分支C优先怀疑代理供应商。检查该供应商的IP段是否被批量标记(可以用一个无关紧要的测试账户去验证),以及近期是否有过静默的出口切换。有一次我们全线异常,查了两天,后来发现是供应商把某个机房的出口从原来的ISP换成了一个新的ASN,而这个ASN在几家风控库里的信誉分很低。
异常表现 |
优先怀疑层 |
验证动作 |
单账户被停用 |
账户层与内容层 |
干净环境复登验证 |
多账户72小时内相继异常 |
账户层与支付层 |
列共同点按强度拆 |
全部账户同时异常 |
基础设施与代理 |
测试账户验出口 |
登录即要求身份验证 |
环境层与出口IP |
核对Geo与历史出口 |
广告审核通过后秒拒 |
内容层与落地页 |
检查Lander可达性 |
Pixel事件回传中断 |
追踪链路 |
查CAPI回传日志 |
表7 归因对照表,配合上面的三分支决策树使用
联盟营销的环境工程,本质是在做关联边的削减,而不是在做身份的隐藏。你削掉的每一条边,都要拿真金白银的成本去换;削到什么程度收手,是个经济学问题,不是技术问题。
回到开头那个问题——做联盟营销该选哪款工具。我的答案是:这个问题的权重被高估了。在表1的五层信号里,浏览器工具能覆盖的是环境层,权重排第三。选一款内核层做过真实改造、有稳定本地API、TLS和HTTP/2层不穿帮的工具,就已经解决了这一层的大部分问题;剩下的四层,工具帮不上忙。
具体到2026年的选型,我会按这个顺序看:内核改造是否触及C++源码层(而不是靠JS注入覆盖属性)、是否提供本地API且文档可用、是否原生屏蔽WebRTC并有独立的DNS防泄露处理、Offer结构是否需要移动端环境、以及团队规模是否需要角色权限和操作日志审计。