|
做社媒多账号的人,多半都踩过同一个坑:IP明明换干净了,一个号出问题,边上三五个号跟着一起被要求验证。于是继续加代理、继续换出口,也有人开始用MostLogin这类多账号环境管理工具把浏览器环境拆开,钱花了一轮,连坐照旧。 问题出在判断模型上。平台风控看的从来不是"这个账号像不像机器人"这么单一的事,它看的是"这几个账号之间,有没有可以连起来的边"。IP只是其中一条边的载体。你在网络层做得很彻底,设备节点那条边、支付资产那条边、行为同相位那条边一条都没断,图谱里这几个账号依然在同一个连通分量里。连通分量一旦被判定为异常,处罚是按分量下发的,不是按节点下发的。 这就是为什么"换IP"经常没用。不是IP不重要,是它只是四分之一的工程量。 把这件事讲清楚,需要一张图。下面这篇就用图论的视角,把账号、设备、IP、邮箱、手机号、支付工具抽象成节点,把"共同登录、共同支付、互相互动"抽象成边,看清楚关联到底是怎么扩散的,以及环境隔离这类工具(比如MostLogin这类多账号环境管理工具)在这张图上究竟切断了哪一条边。 一、把多账号运营画成一张图 1.1节点:平台能看到的一切身份载体 先定义节点。平台在每一次请求、每一次登录、每一次支付里能采集到的身份载体,都可以抽象成一个节点。节点不等于账号,账号只是其中一类。 | | | | | | | | | | Canvas、WebGL、AudioContext、字体列表等前端接口 | | | | | | | | | | | | | | | | | |
这张表里最容易被忽略的是资产节点和内容节点。很多人把全部预算投在网络节点上,因为网络最容易改、见效最快。但资产节点在图谱里的权重通常更高:两个账号绑了同一个手机号,这条边是平台自己数据库里的硬记录,不依赖任何推测模型,也不需要任何指纹技术,查询一次就能拿到。 反过来,网络节点的可信度在这些年里一直在下降。数据中心IP段、住宅代理池、移动基站出口,平台手里都有ASN与IP段的信誉库。一个IP上挂过多少账号、这些账号的平均存活时长是多少,平台比你还清楚。 1.2边:把两个节点连起来的证据 有了节点,边就是"这两个节点之间发生过关系"的证据。边的来源分两类:一类是平台直接记录的确定性关系,另一类是模型推断的概率性关系。 边的确定性差别很大。资产边和互动边是确定性的,平台不需要任何模型,直接查库就有。登录边、网络边也接近确定,只是需要一点指纹或日志技术。行为边和时间边是概率性的,靠模型打分,但这两类边在过去三年里权重上升得很快,因为平台侧的行为建模能力变强了。 还有一个容易被低估的现象:弱边累积。单看一条互动边,权重可能不高;单看一条时间边,也不足以触发处罚。但当十几条弱边同时存在于两个节点之间时,图算法算出来的"连接强度"会远超过任何一条边的阈值。这就是很多人困惑的地方:我明明什么都没共用啊,怎么还是被连起来了。你没共用强边,但你共用了一堆弱边。 1.3一张文本示意图 把上面的定义落到具体场景。假设一个五人运营小组,管着8个账号,用了两条代理线,复用了两台电脑,两个账号共用一个收款账户。抽象出来大概是这个样子: 代码示例(text) [设备节点D1]─────┐ /|\│ /|\│ [账号A][账号B][账号C]│ |||│ |||│ [网络节点IP1]||│ \|/│ \|/│ [资产节点M1:收款账户]│ |│ [账号D]────────────┘ | [网络节点IP2] | ┌─────────┼─────────┐ [账号E][账号F][账号G] ||| └──[互动边:互相关注]──┘ | [内容边:图文相似度0.92] 这张图里有几个值得注意的结构特征。账号A、B、C通过设备节点D1连成一个三角形,任何一处触发判定,另外两个都在两跳之内。账号A、B、C又通过收款账户M1收敛到同一个资产节点,等于两条独立的边指向同一组账号,形成冗余连接。账号E、F、G之间没有共享设备,但它们之间互相有关注关系,又发布了相似度0.92的内容,这是一组典型的弱边簇。 冗余连接是关键。图算法不怕路径长,怕的是路径多。两条独立证据指向同一结论,比分值叠加更致命。 1.4三种典型的扩散路径 把上面的图拆开看,实际运营里最常见的扩散路径有三种。 (1)共享设备节点扩散。多个账号在同一台电脑、同一个浏览器Profile、甚至只是同一个未清理干净的Cookie域下登录过。这条边的采集发生在前端,不依赖网络层,所以换IP完全不影响它。设备指纹的哈希值在几次登录之间保持一致,平台按哈希分组,一组就是一批账号。 (2)共享网络节点扩散。多个账号走同一个出口IP、同一个ASN、甚至只是同一个DNS解析服务器。这条边是服务端日志里最直观的一类,也是大部分人唯一在防的那条。它的局限在于:代理质量本身就是一个信号,频繁切换IP反而会贡献新的可疑边。 (3)共享资产节点扩散。邮箱、手机号、支付卡、收款账户、第三方授权绑定,这类边在注册和支付环节被直接记录,确定性最高,也最难整改。因为它们牵涉到主体信息,改一次的成本远高于换个代理。 这三种路径有一个共同点:它们都在图谱里增加了节点之间的可达性。而环境隔离能处理的,严格说只有第一种。 二、六个平台的判定侧重,其实很不一样 图谱是通用的,但每个平台往图里放哪些节点、给哪些边加权重,差别不小。用同一套配置去覆盖所有平台,是第二类常见错误。 | | | | | Meta系(Facebook/Instagram) | | 账号之间的社交关系与资产结构(共用主页、共用支付方式、共用管理员) | | | | | | | | | | App端读取的设备标识(AndroidID、广告ID、运营商与SIM信息) | | 网页端(卖家后台)可用指纹浏览器;App端需真实移动环境 | | | | | | | | | | | | | | | |
这张表里最值得读的是最后一列。六个平台里,环境层能直接覆盖的部分都集中在设备指纹、存储隔离、网络一致性这几项。社交关系、内容相似度、行为突变,环境工具一件都碰不到。 Meta系是把图谱用得最重的一家。它的判定逻辑里,账号之间的关系本身就是核心证据:共同管理员、共同支付方式、共同商务管理平台资产,这些都在平台自己的数据库里,属于确定性极高的强边。两个账号即使设备、IP、指纹全部不同,只要在同一个商务资产结构里产生过交集,图就画上了。这也是Meta场景下"环境做得再干净也没用"的典型原因,问题出在资产边,不出在设备边。 X的侧重点更像一个突变检测器。它对稳态行为相当宽容,对斜率变化很敏感。一个稳定运营半年的账号每天发二十条,通常没事;一个三天的账号突然从每天两条跳到每天五十条,触发概率会明显上升。这里的信号来源是时间序列,不是指纹。 TikTok是设备权重最高的一家,而且它的移动优先架构决定了网页端指纹覆盖不全。App会读取AndroidID、广告ID、传感器数据、运营商信息,这些根本不在浏览器指纹的参数集里。这类场景要覆盖,只能换载体,用云端真实Android实例或者真机,在网页端调参数是调不出来的。 Reddit对IP段信誉和历史行为格式的看重程度,超出很多人的预期。它对新账号的容错很低,同时对文本格式习惯(标点、换行、链接插入位置)有长周期的建模。 2.1关于小红书,需要把前提说在前面 小红书这一段要写得克制一些。讨论环境隔离的出发点是:运营多个账号时,应当以真实主体、真实内容、真实互动为前提,严格遵守《小红书社区规范》与平台服务协议。多品牌、多门店、多业务线的独立账号,在有真实业务理由的情况下分别配置独立运营环境,本质是资产与权限管理的问题,不是技术对抗的问题。 必须明确的是:不得从事虚假互动,不得发布低质或同质化内容,不得用任何方式制造虚假的互动数据。这几条是红线,任何技术手段都不构成豁免。环境隔离能做的,是让不同主体的账号在设备与网络信号上不互相交叉;它做不到、也不应该被用来掩盖内容同质化或违规互动。如果一组账号被判定异常,先自查内容质量与互动真实性,再去排查环境,这个顺序不能反。 三、环境隔离到底切断了哪条边 3.1它能断的,只有设备节点那条边 回到图谱。环境隔离作用的靶点非常明确:设备节点。一个独立Profile意味着独立的Cookie、LocalStorage、Session、IndexedDB、缓存与代理隧道,多个账号之间的设备指纹哈希不再重合。这条边断了,账号A和账号B在图上就不再通过D1相连。 有几处细节决定这条边断得干不干净。 一是指纹自洽。UA写着Windows,navigator的其他字段却露出macOS;WebGL报告的GPU与声称的显卡型号对不上;屏幕分辨率与设备像素比的组合在真实设备上不存在。这类矛盾本身就是强信号,比指纹相同还可疑。源码层改写与插件注入的差别就在这里:插件注入改的是API返回值,改写不了JS执行栈和渲染管线,交叉验证时容易露馅。 二是扩展与字体。跨环境同步扩展看起来方便,实际上是把一串环境又连回同一个节点。字体列表同理,一个装了冷门字体的环境,本身就是很显眼的特征。 三是代理一致性。指纹是美区Windows,出口IP在东南亚;时区设了东部时间,DNS解析走的却是本地运营商。这类组合在服务端看来是自相矛盾的,比单纯的IP属地问题更刺眼。 3.2它断不了的边,得靠运营规范 剩下的边,环境工具一条都切不掉。 资产边靠主体规划切。邮箱、手机号、支付方式、收款账户按主体分开,这件事在注册之前就要定好,事后改代价极高。 行为边靠操作习惯切。这里有个反直觉的点:多个窗口做同一件事并不可怕,可怕的是它们做得完全同步。 时间边靠排期切。八个账号每天九点整同时发帖,时间戳聚类一下就是一个分量。 内容边靠编辑流程切。同一套素材分发到五个账号,图文相似度模型一算就出来了。 3.3同步器为什么要做"仿人类输入" 说到行为边,就绕不开窗口同步这件事。 主窗口镜像操作到多个次窗口,这个功能本身解决的是效率问题。但朴素的镜像实现有个副作用:所有窗口的动作完全同相位。鼠标在第300毫秒移动到同一个坐标,键盘在第800毫秒按下同一个键,滚动在第1200毫秒走同样的距离。把多个账号的操作序列画在时间轴上,波形几乎完全重合。 这在图谱里是一条标准的行为边,而且强度不低。真实的人类操作者不可能在十个窗口里做出毫秒级同步的动作序列,这个特征太干净了,干净到不像人。 仿人类输入就是冲着这个来的:在按键与点击之间插入随机延迟,官方给出的建议区间是50到100毫秒。加了抖动之后,各窗口的动作序列在时间轴上错开,同相位被打破,波形重合度明显下降。这个延迟区间的取值是有讲究的,太小打不破同相位,太大又会让操作手感变得迟滞,50到100毫秒是个折中。 两个使用上的限制需要提前知道。一是同步器当前仅支持Windows,macOS版本还在开发中,跨平台团队要考虑这一点;二是同步器与MCP都不适用于云手机,云手机侧要走ADB或脚本市场那套。另外,各被同步窗口仍保持各自独立的HTTP(S)/SOCKS5代理,网络边的隔离不会因为开了同步就失效。 需要说清楚的是,仿人类输入只是降低了行为序列的机械感,它不能替代真实的差异化运营。十个窗口发完全相同的内容,加了延迟也一样是内容边。 四、四个维度切分组,三类节奏排日常 4.1四维分组表 分组的原则是让同一组内的账号天然允许有边,不同组之间的账号尽量无边。四个维度一起用:平台、品牌(或主体)、区域、职能。 | | | | | Meta/X/TikTok/小红书/LinkedIn/Reddit | | | | | | | | | | | | | | |
命名规范建议写成"平台-品牌-区域-职能-序号"这种结构,例如X-BRANDHOME-US-CNT-01。命名不是为了好看,是为了三个月后出问题时能在一分钟内定位到那台环境属于谁。 4.2环境配置清单 下面这组参数按区域给三组参考值。字体列表不要随便填,装什么字体就填什么,真实设备的字体列表是有统计分布的,乱填反而异常。 4.3日常操作节奏 节奏表的意义在于切断时间边和行为边。数值没有标准答案,按账号体量调整,重点是"不要所有账号走同一条曲线"。 账号之间互相关注、互相评论这件事,能不做就不做。这是确定性极高的互动边,平台不需要任何模型就能查到。 五、配置示例 5.1环境配置模板 下面这份JSON是单个环境的参数模板,字段命名参考MostLogin客户端的配置项习惯来写,实际字段名以当前版本的官方文档为准。 代码示例(json) { "profileName":"X-BRANDHOME-US-CNT-01", "group":"X/BRANDHOME/US", "platform":"windows", "kernelVersion":"MostChrome-131", "userAgent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/131.0.0.0Safari/537.36", "screen":{ "width":1920, "height":1080, "colorDepth":24, "devicePixelRatio":1.0 }, "timezone":"America/New_York", "language":["en-US","en"], "geolocation":{"mode":"match_proxy","latitude":null,"longitude":null}, "fonts":{ "mode":"system_default", "extra":["MicrosoftYaHei","SimSun","Arial","Calibri","TimesNewRoman"], "disableEntropyFonts":false }, "fingerprint":{ "canvas":"noise_consistent", "webgl":"consistent_with_gpu", "audioContext":"noise_consistent", "webRTC":"replace_with_proxy_ip", "hardwareConcurrency":8, "deviceMemory":8, "doNotTrack":false }, "proxy":{ "type":"http", "host":"us-resi.example.net", "port":8000, "username":"profile_01", "password":"******", "dns":"resolve_via_proxy" }, "storage":{"isolate":true,"persist":true}, "extensions":{"inheritGlobal":false,"list":[]} } 几个字段解释一下。webRTC设成replace_with_proxy_ip,是为了避免真实出口通过RTCPeerConnection的候选地址泄漏出去,这是新手最常见的翻车点。fonts的mode用system_default而不是自定义一堆冷门字体,真实设备的字体分布是有规律的,堆冷门字体等于给自己贴标签。extensions里的inheritGlobal关掉,扩展不要跨环境继承,前面说过,那是把环境重新连回同一个节点的典型方式。 5.2每日巡检脚本 环境建好之后要能验证。下面这段Python用Playwright挂到指定环境的CDP端口上,跑一遍基础一致性检查,把结果写成一行日志。接口路径与字段名以当前客户端版本的文档为准。 代码示例(python) importjson importtime importrequests fromplaywright.sync_apiimportsync_playwright LOCAL_API="http://127.0.0.1:30898" TOKEN="YOUR_MOSTLOGIN_TOKEN" HEADERS={"Content-Type":"application/json","Authorization":f"Bearer{TOKEN}"} defstart_profile(profile_id:str)->str: r=requests.post( f"{LOCAL_API}/api/v1/browser/start", headers=HEADERS, json={"profileId":profile_id}, timeout=30, ) r.raise_for_status() returnr.json()["data"]["debugPort"] defcheck(profile_id:str): port=start_profile(profile_id) withsync_playwright()asp: browser=p.chromium.connect_over_cdp(f"http://127.0.0.1:{port}") ctx=browser.contexts[0] page=ctx.new_page() page.goto("https://ipwho.is/",wait_until="networkidle",timeout=45000) ip_info=json.loads(page.inner_text("pre")) leak=page.evaluate("""()=>newPromise(res=>{ constpc=newRTCPeerConnection({iceServers:[]}); pc.createDataChannel('t'); pc.createOffer().then(o=>pc.setLocalDescription(o)); pc.onicecandidate=e=>{ if(!e.candidate){res([]);return;} res([e.candidate.candidate]); }; setTimeout(()=>res([]),3000); })""") env=page.evaluate("""()=>({ tz:Intl.DateTimeFormat().resolvedOptions().timeZone, lang:navigator.language, dpr:window.devicePixelRatio, cores:navigator.hardwareConcurrency, fonts:document.fonts.size })""") record={ "profile":profile_id, "ts":time.strftime("%Y-%m-%d%H:%M:%S"), "ip":ip_info.get("ip"), "country":ip_info.get("country"), "asn"  ip_info.get("connection")or{}).get("asn"), "tz":env["tz"], "lang":env["lang"], "dpr":env["dpr"], "cores":env["cores"], "webrtc_leak":[cforcinleakifip_info.get("ip")notin(cor"")], } print(json.dumps(record,ensure_ascii=False)) browser.close() if__name__=="__main__": forpidin["X-BRANDHOME-US-CNT-01","X-BRANDHOME-US-CNT-02"]: try: check(pid) exceptExceptionasexc: print(json.dumps({"profile":pid,"error":str(exc)},ensure_ascii=False)) 脚本的核心检查项是三件事:出口IP与配置的时区语言是否对得上、WebRTC候选地址里有没有漏出真实IP、设备像素比与硬件并发数是否与配置一致。跑成日任务,日志留档,出问题时能回溯是哪一天开始偏的。 六、验证与排错 6.1环境一致性自检表 新环境上线前过一遍这十项,任何一项不通过就不要导入账号。 6.2被要求验证之后的处理顺序 收到验证请求先别急着换IP,换得越勤,时间边和行为边越多。按顺序来:确认是单账号还是同组账号同时收到,同组同时收到基本可以判定是图谱扩散;核对最近的资产变更,有没有新绑了什么;检查同组账号之间是否存在互动边和内容边;最后才是环境自查,看代理有没有掉线、指纹有没有因为内核升级而失配。 提交验证材料时给真实信息,用不符合主体的材料去应付,一旦被比对出来,会从节点级处罚升级为分量级处罚。 七、平台检测技术会往哪个方向走 这篇写的是图谱模型,那就顺着这张图往后推几年。 行为建模会从"特征工程"走向"序列建模"。现在的做法多半是人工设计特征:点击间隔的方差、操作序列的熵、访问路径的长度。这些特征对懂行的人来说是可以针对的,你知道平台在看方差,你就能把方差调到正常区间。但当平台开始用序列模型直接对操作流建模时,可针对的特征就消失了,模型学到的是整体形态。仿人类输入这类手段在特征工程阶段有效,到了序列建模阶段,需要的是真正的操作差异化,而不是参数抖动。 图谱关联会向"跨站身份图"演进。这是几家里都在做的事:单一平台内部的数据毕竟有限,当一家公司同时掌握社媒、广告、支付、电商多条产品线时,同一个自然人在不同产品线留下的痕迹可以拼起来。到那个阶段,节点类型的定义会大幅扩展,你在这张图上的位置不再由你自己配置的指纹决定,而由你在多个平台上的历史行为共同决定。 端侧信号的采集会越来越深。浏览器这层的指纹参数已经被研究得差不多了,新的增长点在更下面:真实渲染管线的时序特征、GPU驱动的行为差异、传感器的噪声特征。这些信号的特点是难改,因为它们是硬件和驱动的副产品,不是JS能覆盖的。这也是App端环境比网页端环境更难做的原因,像MostLogin这类同时提供指纹浏览器与云手机两条产品线的形态,本质上是在补这个覆盖缺口。 还有一个不太被提起但影响很大的方向:判定阈值在动态化。平台不会对所有账号用同一套阈值,流量紧张、舆论压力大、监管环境变化的时候,阈值整体收紧,一批原本在灰区的账号会被扫进去。这意味着环境做得再规范,也不能理解为拿到了豁免。规范的环境降低的是无谓的信号噪声,让平台在评估你的时候看到的是一个清晰、一致的身份,而不是一堆互相矛盾的线索。 回到开头那张图。换IP之所以经常没用,是因为它只是从图上拆掉了一条边。真正要做的是让每个账号在图里各自属于独立的连通分量,这件事四分之一的工程在环境层,剩下的在资产规划、内容流程和日常节奏里。
|