
1. 先说清楚Akamai到底在防护什么它的流量入口在哪里很多人一提到Akamai第一反应是“这是个CDN”第二反应才是“它好像还有反爬/风控体系”。实际上Akamai目前的主流业务里CDN只是最底层的一张网真正让安全团队和采集工程师头疼的是架在这张网之上的Bot Manager、Web Application Protector这类云安全产品。本文说的“整体流程”就是一次普通的HTTP请求从用户浏览器出发到真正抵达源站服务器之间Akamai在边缘节点上做过的所有事。理解了这条链路后面所有关于cookie、指纹、JS挑战的讨论才有落脚点。1.1 从DNS调度到边缘节点一次请求先过哪几道关Akamai的流量接入方式和传统CDN不太一样它不只是搞“就近缓存”而是靠自家的Anycast和DNS智能调度系统把用户请求引导到离他最近的边缘节点上。这个节点既是缓存服务器也是安全网关。也就是说请求一旦进入Akamai网络实际上就已经进入了一个可以执行JS、下发挑战、记录行为特征的“黑盒子”环境。整个防护流程的第一个环节是TLS指纹识别。Akamai在边缘节点上会观察TLS握手过程中的细节包括ClientHello里的密码套件顺序、扩展列表、ALPN协议等。如果你用的是一个没有经过专门适配的HTTP客户端库它的TLS指纹往往和真实浏览器差别很大在这一步就会被直接标记为“可疑”后续会被要求做更高强度的验证。这一步是很多采集程序最容易忽略的代码链路跑得好好的请求发出去却莫名其妙拿不到数据其实TLS层早就被识别了。第二个环节是HTTP行为特征识别。这里包括Header顺序、大小写、Cookie的组织方式、是否支持某些特定HTTP/2特性等。真实浏览器通过HTTP/2发送请求时头部压缩和帧排列有非常固定的模式而很多脚本库还在用HTTP/1.1的老套路或虽然用了HTTP/2但细节上“学不像”。这一层相当于安检口的X光机不需要你说谎只要设备客户端长得不像正常旅客就会被单独拎出来。过了这两关之后请求才会进入业务路由判断如果目标是静态资源Akamai可能直接返回缓存不再做更多验证如果目标是HTML页面、API接口或登录会话相关路径并且站点开启了Bot Manager防护则会进入下一阶段的挑战判断。这里有个常见的误解——以为Akamai对所有请求都一视同仁地做高强度验证。实际上它的风控策略是分等级的静态分包、图片请求很多时候连验证都不需要甚至敏感度低的接口也只是“观察但不拦截”。所以搞清楚“站点到底在哪条路径上开了什么级别的防护”往往比埋头研究指纹算法更重要。1.2 无感挑战与显式挑战防护的两种“开火”模式Akamai的挑战机制分成两大类无感挑战Silent Challenge和显式挑战Interactive Challenge。两者的触发条件和用户体验完全不同。无感挑战是最常见的模式。服务端返回一段体积很小的JS脚本浏览器在后台静默执行收集环境信息和操作行为然后通过一个隐藏请求把数据传回去。如果结果通过校验页面自动刷新或继续加载用户几乎感知不到任何异常。这种模式的执行成本低对正常用户零打扰但对自动化工具来说却非常不友好因为挑战是“静默”发生的采集程序往往不知道自己在哪个环节被卡住了。显式挑战则是“开火模式”。用户会看到经典的“Checking your browser”或拼图验证页面必须等待JS完全跑完、甚至需要点击、拖拽或完成一道认知测试才能继续访问。这种模式下的验证强度高每一个交互行为都会被记录和分析。实践中很多被Akamai重度防护的登录接口和核心交易接口用的就是显式挑战因为这类路径的安全优先级最高宁可牺牲部分用户体验也不能放自动化流量进来。需要提醒的是无感和显式挑战经常混合使用。首次访问可能只做无感挑战但如果在短时间内频繁请求敏感接口或者某个请求的TLS指纹、Cookie状态有异常防护等级会动态升级从无感挑战升为显式挑战。很多采集项目的失败恰恰就发生在“一开始跑得好好的过一段时间突然开始频繁出现验证页面”这种动态升级过程中。所以理解Akamai的整体流程不只是记住几个Cookie的名字而是要建立“边缘节点永远在动态评估请求风险”的认知模型。2. 核心命门_abck整个防护体系的“通关文牒”聊到Akamai的防护体系绕不开一个核心Cookie_abck。这是一个所有深入接触过Akamai的人都会反复打交道的字段也是整个防护体系里最关键的“通关文牒”。简单理解_abck是服务端根据浏览器执行JS后提交的传感器数据运算并签发的一个带加密信息的Cookie。后续每一次请求边缘节点都会检查这个Cookie的状态判断“这个会话是不是一个可信赖的真实浏览器”。2.1 _abck的生成时机与生命周期_abck不是一开始就存在的。首次访问受保护站点时如果触发了无感挑战Akamai会返回一段JS脚本这段脚本会在浏览器里收集环境数据和行为数据打包成加密数据后通过特定的验证接口提交。服务端校验通过后会在响应中通过Set-Cookie的方式种下_abck。_abck的生命周期不是固定的通常以分钟为单位动态续期。这很关键——它不是一次性静态凭证而是像一把会定期换锁芯的钥匙。即便你的环境模拟得很完美如果_abck过期了或者请求间隔和续期节奏不正常防护系统也会判定为“可疑会话”。很多人在实际测试中遇到的现象是换一个新环境能正常访问几分钟但只要让请求暂停一段时间再继续立刻被打回验证页就是这个机制在起作用。另一个容易被忽略的点是_abck与TLS指纹、HTTP/2指纹是绑定的。也就是说Akamai在服务端维护的不是“这个浏览器有一个合法的_abck”而是“这个_abck属于具备特定指纹特征的客户端”。如果后续请求的TLS指纹和种Cookie时记录的不一致_abck会被视为不匹配立刻失效。这意味着单纯用浏览器拿到_abck再丢给编程HTTP库去复用绝大多数情况下是行不通的。真实浏览器环境、真实网络协议栈、真实Cookie存储三者必须保持一致才有可能通过校验。2.2 校验维度一次性校验、滚动校验与时间窗_abck校验的核心逻辑可以拆成三个维度一次性校验one-time check、滚动校验rolling check和时间窗校验time-window check。一次性校验比较好理解每个_abck可能在服务端关联一小组一次性令牌用过即废。如果同一个_abck被重复提交到验证接口或者被用于远超正常频率的请求服务端能直接识别出来。这类校验主要针对“复制Cookie”的简单绕过思路。滚动校验则是把_abck当成一个不断变化的动态签名。它的值会随着时间推移和请求行为变化而更新而不是固定不变。实践中很多采集项目发现“Cookie是新的、指纹也模拟了、但跑几分钟后还是会掉线”原因就在于客户端没有跟随服务端下发的更新指令刷新_abck滚动校验失败。时间窗校验关注的是“从种Cookie到当前请求”以及“相邻两次请求之间的间隔”是否符合真实浏览器的行为特征。比如一个正常用户的会话里_abck不可能在几毫秒内连续被使用上百次同理两个请求之间的间隔也不可能像定时器一样精确无波动。时间窗校验防的是那些“拿到Cookie后完全机械化地高频调用”的行为模式。这三个维度叠加起来基本等于告诉自动化工具光靠拿到一个看似合法的Cookie是远远不够的还必须让整个会话的动态行为、更新节奏、请求间隔都“看起来像一个活人在操作”。2.3 配套Cookie家族bm_sz、ak_bmsc、bm_mi各自的作用除了_abckAkamai体系里还有一组常驻Cookie它们各自承担着不同的检测任务经常在浏览器开发者工具里成批出现。bm_sz是“会话指纹”的存根它在Challenge JS执行之前就已经种下主要记录用户代理、基础环境哈希、首次访问时间等信息。可以把它理解成一套会话的“登记台账”即使后续挑战失败或者_abck过期服务端也可以通过bm_sz回溯这个会话的历史信息判断它是不是一个旧嫌疑人。它的生命周期很短通常半小时到两小时不等过期后就会被新的Challenge JS重新种下。ak_bmsc是和_abck联动最紧密的Cookie。它的作用偏“短期会话状态”负责记录无感挑战的进行状态、完成次数、当前会话是否处于“已通过验证”的状态。在一个正常会话中_abck负责最终合法性ak_bmsc负责中间过程的状态维护。有些时候即使_abck没有被更新为最新值只要ak_bmsc的状态还在有效期内请求依然能通过低等级防护路径。bm_mi则是一个与用户“真实性”相关的标记它从鼠标移动、触摸事件、键盘输入等交互行为中提取特征生成一段行为签名。这个Cookie的存在说明了Akamai的一个核心设计思路它不仅仅验证“你是不是浏览器”更验证“你是不是一个正在像人一样操作的人”。纯程序化的请求往往缺少动态的交互数据bm_mi就成为一个重要的补充判定依据。所以单纯盯着_abck是不够的。真正的完整流程里_abck只是最终结果bm_sz、ak_bmsc、bm_mi则是过程中的“证据链”。服务端判断一次请求是否可信看的是这一组Cookie形成的整体状态而不是某一个单独字段。3. 传感器数据sensor_data的秘密浏览器指纹是这样被“招供”的要理解Akamai的挑战机制就必须弄明白浏览器到底向服务端“招供”了什么。Akamai把采集到的数据打包成一个对象业内习惯称之为sensor_data。这个名字在网络上曝光率极高几乎成了Akamai逆向的代名词。它之所以重要是因为_abck的签发、校验、更新几乎都依赖sensor_data里的内容。3.1 传感器数据里到底装了什么sensor_data是一个JSON结构但从加密和混淆程度上看它绝不是把明文平铺给你看。里面通常包含几个大的部分环境设备信息包括屏幕分辨率、色深、时间偏移、操作系统语言、User-Agent、浏览器版本以及通过canvas和WebGL渲染得到的图像哈希。这类信息用来确认“浏览器运行在什么样的设备上”。能力检测结果比如是否支持ActiveX、是否支持特定CSS属性、WebRTC的可用性、AudioContext产生的音频指纹等。很多无头浏览器和模拟环境在这些细节上会与现实浏览器产生差异。交互轨迹包括鼠标移动路径、点击位置、触摸事件、滚动速度、键盘输入间隔。Akamai从这些数据中提取人机行为特征比如移动曲线是否过于平滑机器人常有的特征、两次点击之间的时间分布是否符合人类操作习惯。时序数据记录页面加载到挑战执行完成期间的各种时间戳包括JS执行耗时、网络请求响应间隔等。这些数据用于检测是否存在“时间加速”或“执行过程异常缩短”的情况。真正让自动化工具头疼的不是单个字段的伪造难度而是字段之间的关联性。比如一个模拟浏览器声称自己跑在Windows系统上但其WebGL渲染哈希却与Windows平台常见的GPU驱动特征不符这就会被判定为矛盾数据。又比如sensor_data里记录的鼠标轨迹非常平滑、速度恒定这在真实人类操作中几乎不可能出现同样会拉高风险分。3.2 数据采集的时机与上报链路为什么不能“只提交一次”很多新手会有一个直觉既然sensor_data是用来种_abck的那我只要拿到所有环境数据打包提交一次得到一个合法的_abck不就一劳永逸了吗实际完全不是这样。Akamai的设计里sensor_data的采集是持续进行的。挑战JS会在页面生命周期内一次性完成初始采集并上报但这只是建立“初始可信”。随后浏览器在后台还会持续采集用户的动态行为并在合适的时机比如页面切换、点击、滚动停顿再次上报增量数据。服务端会把这些增量的行为数据与_abck的滚动更新绑定起来。换句话说_abck的每次“续签”背后都可能对应一次sensor_data增量上报。这个设计直接导致了一个后果只提交一次传感器数据确实能生成一个可用的_abck但它的“有效期”和“信任等级”都有限。一旦检测到高频请求、长时间静默、或请求间隔与人类行为不符就会触发一次新的挑战要求再次生成和上报sensor_data。很多采集项目明明已经实现了sensor_data的完整生成却还是在运行几小时后崩溃原因就在于没有处理好“持续上报”和“滚动更新”这条链路。所以在整体流程里sensor_data更像是一条不间断的“心跳线”而不仅仅是一张入场券。理解了这一点回头看Akamai的防护逻辑它其实是在模拟一种非常朴素的信任机制我不光看你是不是一个人我还看你是不是一直“像人一样活着”。4. 一次完整挑战交互过程的拆解前面把Cookie、传感器数据分别讲了一遍现在把这些拼起来串一条完整的时间线。理解了这条时间线才能真正把“整体流程”这四个字落到地上。4.1 请求被拦截后的完整交互时序假设一个用户首次访问一个受Akamai防护的站点整个过程大致是这样浏览器发起页面请求请求先到达Akamai边缘节点。边缘节点检查当前会话状态没有_abck也没有其他有效的信任Cookie判断为“冷启动”请求。边缘节点不直接返回业务页面而是返回一个带有Challenge JS脚本的响应。响应头里往往包含Set-Cookie: bm_sz...和ak_bmsc...先建立会话存根。浏览器加载并执行Challenge JS。JS内部开始做两件事一是收集环境指纹二是绑定用户交互事件积累行为数据。JS执行完毕后将包含环境数据和初始行为数据的sensor_data通过一个异步请求提交到验证端点。这个端点通常是/akamai/...、/_sec/cp_challenge/...这类不对外公开的路径具体路径随版本演进不断变化。服务端校验sensor_data。校验内容包括数据格式、加密签名、字段一致性、时间戳合理性、以及是否存在已知的自动化痕迹。校验通过后服务端返回一段加密信号浏览器侧的JS解析后执行一次页面刷新或继续加载操作同时服务端通过响应头种下_abck。后续请求携带_abck继续访问。边缘节点对每个请求都做快速校验包括Cookie合法性、请求频率、TLS指纹一致性等。整个流程从用户视角看就是“打开页面可能闪一下”但实际后台已经完成了一整套“登记、盘问、发证”的操作。4.2 token生成、提交与校验在Challenge流程中sensor_data并不是直接以明文JSON传输的。Akamai有一套自己的加密和编码机制常见的形态是经过Base64编码和自定义混淆的字符串。提交时浏览器会构造一个POST请求Payload里的关键字段就是这一坨编码后的数据。服务端拿到之后要做几层解析第一层是基础解码还原成原始格式第二层是解密或反混淆提取出真正的结构化数据第三层是签名校验确认数据在传输过程中没有被篡改第四层才是内容校验也就是逐一核对前面提到的环境信息、行为轨迹、时间戳序列。这里有个关键点Akamai的JS代码通常经过重度混淆变量名随机化、控制流扁平化、字符串加密都是基本操作。而且它更新频繁旧版本的JS会在几天甚至几小时内被替换。这意味着如果你在研究中使用了“硬编码解密逻辑”的方案一旦JS更新整套流程就得重新逆一遍。这也是为什么很多团队最终会放弃“离线逆向”转而采用“保持真实浏览器环境、走完整交互链路”的方案——后者的维护成本远低于前者。4.3 实测中容易“露馅”的细节我在实际测试过程中整理过一份“容易露馅”的检查清单这里分享几个高发问题第一WebDriver痕迹。很多自动化框架会在浏览器里留下webdriver属性的标记Akamai的Challenge JS会主动探测这个属性。哪怕你已经隐藏了绝大多数特征只要这一项没处理干净sensor_data里就会有明显的自动化标记。第二鼠标轨迹的“过度平滑”。如果用程序模拟鼠标移动轨迹常常是直线或非常完美的贝塞尔曲线速度变化均匀。但真实人类的鼠标轨迹有抖动、有停顿、有加速度突变这些细节在数学特征上一眼就能看出来。很多采集项目栽在这个“看起来太完美”的细节上。第三时间戳的“整点效应”。真实浏览器的JS执行时间、requestAnimationFrame回调间隔都存在自然的波动。如果程序严格按照固定间隔采集和上报数据时间戳序列会呈现出机器特有的周期性这在相关性分析下非常显眼。第四环境矛盾。比如sensor_data里上报的屏幕分辨率是1920x1080但鼠标轨迹的最大坐标却超过1920或者上报的语言环境是en-US但系统时区却是UTC8。这类自我矛盾的数据几乎等于主动承认“我在撒谎”。这些细节单独看都不致命但Akamai是带风控模型的它会把这些小瑕疵汇总成风险分。当风险分超过阈值_abck的信任等级就会下降最终表现为“请求被拦”或“被要求重新验证”。5. 服务端的风险判定逻辑它不是只看指纹sensor_data、_abck这些东西聊多了容易让人产生一个误区以为只要把这些技术参数模拟到位Akamai就会放行。但Akamai作为商业风控产品它的判定逻辑是成体系的技术参数只是其中一个维度。5.1 请求信誉分与行为维度的权重Akamai在服务端维护着大量的威胁情报和信誉库。一个IP是数据中心IP还是住宅IP历史上有没有参与过攻击行为在最近一段时间内是否被大量账号注册/登录接口调用过这些都会直接影响请求的初始信任分。这意味着即使你的浏览器指纹模拟得完美无缺只要你从某个数据中心IP发出高频请求Akamai依然可能选择干预。反过来如果你从一个信誉良好的住宅IP出发哪怕指纹上有一些小瑕疵可能也不会被立刻拦截。我把这个逻辑称为“初始信任加权”——指纹决定“你是不是一个合格的人”信誉库决定“这个人是否值得被信任”。行为维度也很重要。一个正常用户一天访问某个站点的频率是有自然上限的接口调用顺序也是遵循页面逻辑的。如果一段会话里登录、搜索、下单接口的调用顺序和频率完全脱离了正常用户的浏览路径即便每个单独请求都通过了校验整体会话的风险分也会被拉高。这就是为什么很多采集方案会强调“限速”和“模拟真实操作路径”而不只是调好一个指纹就无脑发请求。5.2 为什么“指纹正确”仍然会被拦截我见过不少团队花费大量精力把sensor_data的生成、_abck的滚动更新全部搞定却在正式运行时发现拦截率依然居高不下。这时候通常要排查的不是指纹而是“宏观特征”。常见的宏观特征包括单IP发起的并发连接数真实浏览器与站点之间的并发连接是有限的远超合理值的并发本身就是异常。同一IP下TLS指纹的单一性如果某个IP的所有请求都来自同一个TLS指纹而且这个指纹在24小时内持续高频活跃这基本就是脚本特征。会话时长的异常集中比如大量会话都在凌晨某个固定时段出现并且集中访问单个接口不符合人类用户的作息和浏览规律。所以Akamai的整体流程本质上是一个多层次的风险决策引擎。指纹sensor_data/_abck是第一层准入IP信誉和宏观流量特征是第二层环境判断行为路径和请求节奏是第三层意图分析。只把注意力放在第一层等于只看到了一座冰山的水上部分。6. 理解了这套流程之后对防护与采集双方的启示把Akamai的流程拆解到这不只是为了满足好奇心。对不同类型的从业者这套流程能给出非常有价值的决策依据。6.1 从防御方视角看什么样的防护才是有效的如果你正好在做自家站点的安全防护工作Akamai这套体系至少说明了几个关键原则第一单点验证永远不够。如果只依赖一个随机token或者一个简单的验证码攻破成本太低。有效的防护必须是多点联动的TLS指纹、行为轨迹、Cookie状态、IP信誉、宏观节奏各层互相校验任何一层缺失都能拉高风险分。第二动态挑战优于一次性验证。Akamai的滚动更新机制本质上是让“信任”变成一个动态过程而不是一个静态结果。静态凭证可以被复制、被复用但动态会话很难被完整克隆。防护体系设计时尽量让验证状态持续变化、持续要求客户端“证明自己是活的”。第三JS挑战能把大量自动化流量挡在门外。虽然理论上可以逆向JS但维护成本很高。对大多数攻击者和采集者来说一个更新频繁、混淆程度高的JS挑战已经足以劝退很多人。这也是云WAF产品普遍采用JS挑战的原因——它不是一个“不可能绕过”的方案而是一个“获得通过成本远高于收益”的方案。6.2 从研究视角看这套流程里真正值得下功夫的地方对做技术研究或者业务数据获取的朋友我的建议是不要把精力全放在“硬破解”sensor_data上。从工程维护的角度看基于真实浏览器环境的完整交互方案反而更可持续。关键要下功夫的地方有三块一是真实浏览器环境的稳定性。包括TLS指纹、HTTP/2指纹、Canvas/WebGL渲染结果、字体列表、插件支持情况这些环境特征必须保持高度一致性任何一环的偏差都可能被风险模型捕捉。二是行为模拟的自然度。限速、随机间隔、鼠标轨迹抖动、点击停顿、偶尔的滚动中断这些细节决定了sensor_data里的行为数据是否“像人”。三是动态更新响应能力。监控Akamai JS的版本变化能在新版本上线后快速感知并调整环境配置。而不是一次性搞定然后祈祷它永远不变。我在实际操作过程中最深的体会是Akamai整体流程虽然复杂但它的核心始终是对“一致性”和“持续性”的考察。它很少因为你某一个点做得不好就立刻判死刑而是通过多维度的风险累计来决定是否干预。反过来这给研究者和防御者都留出了空间——只要你愿意把细节做到位把节奏控制好大部分场景下是可以与这套体系共存的。如果你只是想要“一把梭”的破解方案那大概率会在这套动态博弈里反复折腾疲劳不堪。