Dev.to Security 🔐 Cybersecurity 👁 0

每个 URL 都是先收到一次 code=37 触发前端安全js然后才能得到职位列表

先实际跑一次,记录 code=37 前后的完整流程 先实际跑一次,记下 code=37 前后 Cookie、页面跳转和加载了哪些脚本,免得只凭推测解释。 code=37 是 BOSS 对"没有 __zp_stoken__ Cookie 的请求"给出的回应,相当于让页面先通过一轮安全校验再来。页面拿到它后会自己跳到校验页,算出 Cookie,再跳回来重新请求,这次就返回 code=0 和职位数据。 我们每个 URL 都新建一个

先实际跑一次,记录 code=37 前后的完整流程

先实际跑一次,记下 code=37 前后 Cookie、页面跳转和加载了哪些脚本,免得只凭推测解释。

code=37 是 BOSS 对"没有 __zp_stoken__ Cookie 的请求"给出的回应,相当于让页面先通过一轮安全校验再来。页面拿到它后会自己跳到校验页,算出 Cookie,再跳回来重新请求,这次就返回 code=0 和职位数据。

我们每个 URL 都新建一个干净的浏览器 context,没有任何 Cookie,所以每个 URL 都要走一遍这个流程。

我刚在本地跑了一次,用同样的 CDP 拦截记录了整个过程。

一、实测时间线

时间 事件 关键信息
0.9s 打开 /web/geek/jobs?... Cookie: 无
3.1s 加载 /zhipin-security/web/geek/index.js ← 前端安全脚本
3.6s joblist.json → code=37 请求头里没有 __zp_stoken__;返回 zpData = { seed, name, ts }
3.8s 页面自己跳转到 /web/passport/zp/security.html?callbackUrl=原页面 进入校验页
4.2s 加载 /web/passport/zp/security-js/d0acb6be.js ← 文件名就是上面返回的 name
4.8s 页面自己跳回原页面,URL 多了 &_security_check=1_<时间戳> 回到职位列表
5.4s joblist.json → code=0,返回 jobList 请求头里带上了 __zp_stoken__
17.9s Cookie 里出现 __zp_stoken__、__a、__c、__g、__l、ab_guid 等 —

二、各步骤的作用

步骤 观察到的现象 作用
1. 首次请求 joblist.json 不带 __zp_stoken__ 服务器没有凭证,无法确认来访者
2. 返回 37 {"code":37,"message":"您的环境存在异常.","zpData":{"seed":...,"name":"d0acb6be","ts":...}} 不给数据,而是下发一道"考题":随机的 seed、时间戳 ts,以及用哪个算法脚本 name
3. 跳转校验页 security.html?callbackUrl=... 进入专门的校验页面
4. 加载算法脚本 security-js/d0acb6be.js 根据 seed 和 ts 计算 __zp_stoken__ 并写进 Cookie
5. 跳回原页面 带 _security_check=1_<ts> 回到职位列表
6. 再次请求 请求头带 __zp_stoken__,返回 code=0 校验通过,拿到数据

第 4 步脚本具体算了什么,是根据现象和社区对 BOSS 的公开分析推断的,我没有逆向 d0acb6be.js。这类脚本通常会混淆代码,并采集浏览器环境特征,比如 navigator、webdriver 标记、canvas 等,把这些特征和 seed、ts 一起参与计算。所以靠 requests 这类没有真实浏览器环境的工具很难生成合法的 Cookie。这也是项目必须用真实 Chrome 的原因。

另外两次运行的 name 都是 d0acb6be,seed 每次都不同。可以推测 name 是算法脚本的版本号,BOSS 可能定期更换,而 seed 是每次随机下发的。

三、为什么说它是"正常步骤"

  1. 真实用户第一次访问也会遇到。 新浏览器、清过 Cookie,或者 __zp_stoken__ 过期了,都会走这个流程,只是跳转很快,人察觉不到。

  2. 我们的程序每个 URL 都会遇到。 process_page_request 里每个 URL 都调用 browser.new_context(...) 新建一个隔离的 context,上一个 URL 拿到的 Cookie 不会带过来。

  3. 能通过就说明环境没被识别出来。 如果被判定为机器,后续请求会一直返回 37,或者跳到验证码页,不会变成 code=0。所以日志里出现一次 37、紧接着拿到数据,是正常的。真正需要警惕的是同一个 URL 连续多次 37 都没有恢复。

四、这次实测的两个额外发现

1. 当初"响应体不可用"的主要原因是反爬跳转

从时间线可以看到,页面在 2 秒内自己跳转了 3 次:原页面 → security.html → 带 _security_check 的原页面。每次跳转,Chrome 都会丢弃上一个页面的响应数据。

旧代码用 page.on('response') 再去读 body,正好赶上这几次跳转,所以最开始那个报错不只是 goto 后马上 reload 造成的。现在的 CDP 方案在数据交给页面之前就取走了,不受这些跳转影响。

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.