ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

F5 Shape SDK逆向分析:从采集机制到误杀排查全解

F5 Shape SDK逆向分析:从采集机制到误杀排查全解 搞过风控对抗或者Bot防护的人估计都见过这场景某天早上站点忽然涌进大量客服投诉说正常用户总是被弹验证、登录死活过不去。问题查来查去最后定位到页面里多了一段来自shape.security或f5-dfcs.com的脚本。F5 Shape这套东西在美西南这类航旅站点、以及我那代号xbk的测试环境里出现的频率是真的高。标题里说的“逆向分析”不是要绕过它去搞什么灰产而是作为安全研究员或者甲方风控必须搞清楚它到底采集了什么、决策链路长什么样、误杀是怎么来的。这篇文章就是我近期对F5 Shape最新版SDK做机制拆解的完整记录从抓包到解混淆再到美西南和xbk两种场景下的信号差异最后落到防御协作和误杀排查。1. 为什么会盯上F5 Shape一次“被误封”的排查现场1.1 误封现象与第一反应凌晨三点告警群突然响起来接口成功率从99.9%掉到70%出头。第一反应是回源出问题了或者是CDN的某个节点抽风。但打开流量看发现大量来自住宅宽带的正常会话都拿到了一个challenge响应紧接着页面就被插入了一段图灵测试。这种“大规模误杀”的典型特征基本就在提示我们机器人防护系统的策略被某个信号击穿了导致正常用户被连带拦截。排查初期的常见错误是盯着应用日志找异常但应用层根本没有错误——请求都正常到达了后端只是在更前置的Bot防御层被扣下了。再到响应头一看Set-Cookie里出现了__shape_a、__shape_b这一串东西才确认是F5 Shape在起作用。平时它是隐形防守者一旦误杀就成了最大的背锅侠。1.2 Shape不是单点而是一条完整决策链很多刚从应用防护转过来的人会把F5 Shape理解成一个“JS脚本”以为去掉脚本就绕过了。这是最大的误区。我前前后后分析过几次Shape这套东西拆开来看至少四层采集层下发到浏览器的SDK负责采集设备指纹、行为轨迹、DOM环境等信息。保护层SDK自带代码混淆、反调试、反模拟机制防止被人直接抄作业。决策层采集到的数据上传到F5的云端模型服务端结合IP信誉、历史行为、会话风险等给出 allow / challenge / block 的结论。执行层结论通过Set-Cookie、页面注入、API响应头传回浏览器决定是放行、弹验证还是拒绝。这套结构的核心在于前端SDK只是收集端真正的判定逻辑在云端。只盯着JS看等于只拿到了整条链路的20%。很多做逆向分享的人喜欢把SDK里的字符串解出来贴一堆看起来很厉害但离“搞懂这套东西”还有很长的距离。2. Shape系最新版SDK的可观察特征从入口脚本到下发链路2.1 SDK入口的加载方式与识别要点被Shape保护的站点入口脚本不一定叫shape.js新旧版本差异不小。老版本常见的是直接加载https://*.shape.security/script/v1/...而新版本统一走F5分布式云体系域名经常是*.f5-dfcs.com有时还会套一层CloudFront这类CDN做分发脚本名有时还带随机化参数。单凭脚本文件名判断版本很容易翻车。观察入口要从三个层面入手加载方式同步加载还是异步加载、是否带defer、是否在DOMContentLoaded之后才动态插入。版本探测SDK初始化时会向服务端发一个配置请求响应里通常包含当前下发版本号、启用的检测模块列表、灰度开关等。这是判断“最新版”最直接的途径。脚本内容特征主脚本里会有分片加载逻辑新版手感和旧版完全不一样。提示新版SDK的版本控制是灰度制的。美西南这种大流量站点同一时间线上可能同时在跑两三个不同版本不同地区、不同会话拿到的脚本也不一样。分析时如果只缓存了一份样本得出的结论可能就是错的。2.2 新版与老版的核心差异结合我这段时间对美西南站点和xbk环境的观察最新版相对上一代至少有四个明显变化第一脚本从单文件变成了分片加载。老版一个shape.js从头到尾新版的模块被拆成多个chunk运行时按需拉取哪些模块被加载取决于页面类型和环境特征。这在分析时要多看好几个请求工作量直接翻倍。第二遥测接口的路径变成了动态签名。老版上报数据的URL相对固定可以比较容易地抓到完整数据包。新版上报路径带一次性签名参数并且report、config、challenge走不同的端点光靠抓包把所有请求拼齐就需要不少耐心。第三检测点大量挪进了Web Worker。新版把一部分采集逻辑放到了独立的Worker线程里跑主线程代码被混淆后基本看不出采集逻辑。调试时如果不开Worker的线程面板很容易漏掉关键上报点。第四关键数据不再直接写进Cookie。老版本里有一段时间部分特征会被编码塞进Cookie存在本地。新版Cookie里存的多半是临时票据或一次性token真正关键的状态全部服务端掌握。这意味着想靠纯前端分析伪造出一个“合法Cookie”来直接过关基本是走不通的新版的判定核心已经彻底云端化了。2.3 服务端决策的响应形态SDK跑完采集服务端的结果最终要传递到浏览器和业务方常见的有几种形式响应形态常见标记典型含义变更频率Set-Cookie__shape_a短期会话标记生命周期短每次会话/请求级刷新Set-Cookie__shape_b长期设备标记生命周期长相对稳定Set-Cookie__shape_shape验证状态相关出现它说明策略介入触发验证/解除验证时变化响应头shape-render-mode等指示前端以何种方式渲染验证策略变更时变化页面注入动态插入的challenge JS触发人机验证界面命中策略时出现排障的时候关键在于分清“它到底只是给你打了标记还是已经发了验证指令”。前者往往只是常规采集后者才是用户被卡住的直接原因。如果发现__shape_a和__shape_shape同时出现且策略ID在变化多半是会话风险分在动态调整。3. 实际逆向分析流程抓包、断点、AST解混淆、行为验证3.1 环境与工具链选型做这类分析环境干净比技术本身更重要。我常用的组合是抓包Charles或mitmproxy用于看完整请求链路重点记录SDK的配置请求、上报请求、Cookie变化顺序。浏览器调试Chrome DevTools配合断点看JS运行时的调用栈。代码美化与解混淆js-beautify负责格式化Babel或ast-grep负责AST级别的结构还原。行为对照Puppeteer/Playwright用来造不同指纹、不同行为模式的浏览器环境做对比实验。注意整个分析过程必须限定在已授权范围内比如自建测试环境、与防护厂家的合作项目或者你对美西南这类第三方站点做的是“仅观察不干扰”的被动分析。任何插件注入、流量修改、验证尝试都必须有授权依据这是基本底线。3.2 定位关键函数的完整链路实际动手时我会按下面的顺序把链路完整走一遍这也是我觉得最有价值的一套方法论而不是某个特定版本的特征第一步找到SDK入口保存脚本。在DevTools里过滤shape或f5定位到主脚本URL保存后先跑js-beautify格式化把压缩成一行的大文件还原成可读结构。第二步特征字符串地毯式搜索。打开格式化后的代码搜canvas、getBattery、mouse、touchstart、sendBeacon、XMLHttpRequest、localStorage、indexedDB这些关键词。新版混淆比较狠字符串经常是动态拼的但关键API名总会出现在某个不太起眼的位置。找不到就说明做了字符串数组偏移得用AST还原。第三步在Cookie写入点和网络请求处下断点。打开Sources面板在Document.cookie的setter、sendBeacon、XMLHttpRequest.send、fetch上打断点。刷新页面观察SDK在哪个执行阶段触发了网络请求请求体里带了什么参数。这样能把“采集代码”和“上报时机”对应起来。第四步顺着调用栈找到数据封装函数。从断点往上翻调用栈找出发送前的数据序列化逻辑那里通常是特征打包的地方。新版会用动态属性名做一层包装AST解混淆后字段名还是可能不直观这时候别死磕用“黑盒观测关键节点断点”配合把字段名和实际值对应起来记录一版就够了。第五步对照测试验证权重。这一步最关键。做一个最小环境用不同指纹和行为组合去访问同一个接口记录每次的决策结果反推哪些信号权重高。3.3 解混淆之后看什么采集维度清单地址解完、函数理清以后重点看SDK到底从哪些维度采集数据。我整理了一个常观察的维度表维度类别具体采集点潜在用途基础环境UA、Accept、Accept-Language、时区、语言建立基础画像硬件指纹canvas、WebGL、字体、屏幕分辨率、设备内存、CPU核数识别真实设备存储痕迹localStorage、IndexedDB、Cookie可用性探测判断是否清白历史行为轨迹鼠标、触摸、键盘事件间隔、滚动行为判断“人来操作”还是脚本操作网络特征RTT小包探测、连接类型、Service Worker状态估算网络环境与代理特征环境异常iframe嵌套、窗口尺寸、WebDriver标记、DevTools检测检测浏览器是否被自动化控制这些维度单个看都弱“UA时区屏幕”就能撞出一大片人但组合起来、再叠加服务端的动态模型区分度就上来了。这也是为什么Shape敢把判定全部放云端——因为前端采集的数据本身是“原材料”模型才是“加工厂”。3.4 一个最小观测脚本的思路下面这个脚本目的是复现“把SDK的运行过程录下来”这个动作方便对比不同环境下的行为差异。它不伪造任何东西只是观察// 观测性示例仅用于已授权环境的SDK行为分析 const puppeteer require(puppeteer); (async () { const browser await puppeteer.launch({ headless: false, // 用有头模式尽量接近真实环境 args: [--window-size1366,768] }); const page await browser.newPage(); // 记录SDK相关的请求和响应细节 page.on(response, async (resp) { const url resp.url(); if (url.includes(shape) || url.includes(f5)) { console.log([SDK request], resp.status(), url); } }); // 打开目标URL请替换成你具备分析权限的站点/测试环境 await page.goto(https://your-lab-site.com, { waitUntil: networkidle2, timeout: 60000 }); // 输出当前页面上的shape相关cookie const cookies await page.cookies(); console.log(cookies.filter(c c.name.startsWith(__shape))); await browser.close(); })();跑通之后多准备几组对照环境对照组环境情况常见结果A组有头Chrome正常鼠标移动停留一段时间再操作基本不触发验证B组无头模式、直接发请求、零交互高概率触发challengeC组有头Chromium但自动化标记明显大概率被标记为可疑对照实验的目的不是写一个“逃过检测”的脚本那条路既没意思也没授权而是搞清楚哪些信号权重大、哪些行为最容易触发误杀——这恰恰是甲方排障时最需要的信息。4. 美西南和xbk两种场景下的检测信号差异4.1 站点形态差异对SDK的影响美西南Southwest Airlines这类航旅站点的体量摆在那子域多、业务链路长登录、搜索、支付、会员中心各自都有独立页面。实际观察下来不同子域加载的SDK配置经常不是一套有的页面只加载基础采集版有的页面会额外加载增强验证模块。加上流量大A/B测试和灰度发版几乎全天在线同一个用户上午下午拿到的SDK都可能是不同版本。相比之下xbk是我自己搭的测试站点代号用的是同一家SDK服务但流量小、业务路径短、也没有灰度策略SDK版本相对固定。这带来的一个实际影响是在xbk上分析出的结论不能完全等价套到美西南场景版本差异、策略差异、流量模型差异都可能导致行为信号不一致。4.2 行为阈值会随风险状态动态变化这是我在两个场景里对比之后印象最深的点同样是“没有鼠标移动、快速连续请求”的行为模式在xbk环境可能只是分数上调在美西南环境很可能直接触发验证。这说明服务端不是用的固定规则而是接了实时风险变量——IP信誉、会话新鲜度、请求频率、路径异常度都会影响最终阈值。换句话说同一套采集数据在不同时间、不同入口、不同风险上下文中对应的决策可能完全不同。做逆向分析时如果只拿一次结果下结论很容易被误导。正确打开方式是拉长观测周期记录至少一周的决策结果变化再去找规律。4.3 容易被忽略的网络侧信号除了浏览器端的行为数据Shape服务端还会结合网络侧信息做交叉验证。比较常见的是看到IDC出口IP即使浏览器指纹完全正常也容易进验证队列而住宅宽带、移动网络的用户即使指纹有一点点偏差分也不一定高。这个“网络画像设备指纹”的交叉逻辑是很多误杀的来源。对甲方运维来说这个特性的直接启示是排查误杀不能只让用户“换个浏览器试试”还要看他的出口IP类型和会话建立方式。来自云厂商出口、数据中心出口的办公网用户被Bot防护误伤的概率天然高一些这不是前端能解决的问题只能通过策略白名单或调整阈值来缓解。5. 搞懂机制之后真正能落地的事防御协作与误杀排查5.1 一套完整的误杀排查链路如果你是被Shape保护的站点方最常见的需求不是“分析SDK怎么工作”而是“现在用户被误杀了怎么快速定位”。我踩过几次坑之后总结了这条链路收集现场信息拿到目标用户的UA、IP、访问时间、会话Cookie先确认同一IP段、同一UA模式的用户是否大面积受影响。区分决策类型看响应是challenge弹验证还是block直接拒绝两种处置对应的排查方向完全不同。确认SDK版本让用户清缓存重新加载页面看下发的是哪个版本。如果新版本刚灰度不久误杀概率会显著上升。简单A/B确认在测试环境临时屏蔽SDK模拟相同操作路径看问题是否消失。如果消失了就基本锁定是Bot层的问题要反馈给防护团队。提交加白或调参工单把上面收集的信息整理成证据链联系F5或厂商侧调整策略、加白特定UA/路径或者把风险阈值从严格调回中等。5.2 与风控、研发协作时的日志字段清单误杀排查最怕部门墙风控说“是网络问题”研发说“应用层没报错”安全说“是防护策略误杀”。要打破这个局面关键是大家手里有一份统一的排障日志。建议至少要记录这些字段字段说明时间戳精确到秒保留时区会话ID / 用户标识用于关联前后端日志Shape决策结果allow / challenge / block触发策略ID方便定位是哪些规则生效客户IP脱敏判断是住宅、移动还是IDC出口UA判断是正常浏览器还是自动化工具SDK版本号定位是否灰度新版本引入验证页面URL用户到底是被哪个页面的验证卡住这份清单的意义在于三方都能基于同一组数据说话而不是互相猜。拿到工单的第一时间先看“决策结果”和“触发策略ID”比看一百行应用日志都管用。5.3 几个值得长期观测的健康指标最后建议被防护方把下面几个指标做成日常监控。它们不是单纯看“有没有被攻击”而是看“防护系统有没有误伤良民”两者同等重要challenge率被弹验证的请求占总请求的比例正常波动应该在某个范围突然飙升就是要出事了。验证通过率弹了验证之后有多少人能真正通过过低说明验证门槛太高或策略误杀严重。接口成功率新增或变更防护策略后这个指标是最直观的“用户体验体检表”。SDK加载耗时Shape SDK不算轻量对首屏渲染有可感知的影响建议设一个性能预算。版本号分布保持对线上SDK版本的感知灰度出了问题可以在几小时内止损。这套指标配上前面的排查链路基本能覆盖日常防护运维里90%的误杀场景。我个人在实际项目里的体会是F5 Shape这类云端Bot防护的逆向分析价值不在于“破解一个版本”而在于建立一套长期有效的“版本追踪行为观察误杀排查”机制。今天分析的结果三个月后很可能就因为一次灰度更新全部作废但方法论和分析链路是可以一直复用的。所以我会把每次观察到的版本特征、决策变化、踩坑记录归档成一个持续更新的特征库文档排障时直接查效率比临时翻混淆代码高得多。另外说一句很多讨论会把F5 Shape和F5 BIG-IP、F5 NGINX的漏洞通知混在一起实际上Shape是收购来的独立产品线走的是SaaS化Bot防御订阅和自运维的BIG-IP/Nginx基础设施是两个体系排障时不要混着看不然会白白浪费很多时间。
返回列表