首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >派猫猫旅行巡检自动化 一次 401 鉴权故障的完整排查复盘(续)

派猫猫旅行巡检自动化 一次 401 鉴权故障的完整排查复盘(续)

原创
作者头像
用户12683097
发布于 2026-09-28 08:39:42
发布于 2026-09-28 08:39:42
460
举报

原文档《派猫猫旅行巡检自动化:一次 401 鉴权故障的完整排查复盘》

派猫猫旅行巡检自动化

一次 401 鉴权故障的完整排查复盘(续)

关键词:自动化 · 反爬 · Bearer 鉴权 · Cookie 鉴权 · Chrome DevTools Protocol · App-Bound Encryption · Edge · Keycloak JWT

适合读者:做过"网页自动签到 / 定时脚本 / 浏览器自动化"的开发者;遇到过"脚本突然 401、手动又能访问"这类问题的同学。

【重要】结论更正(2026-09-26,务必先读)本文初稿写于 9/18,当时得出核心结论:"必须用真实浏览器代发才能绕过 EdgeOne 风控指纹封锁"。该结论已被 9/26 的实测推翻。真相是:· 接口鉴权的真因是缺 Authorization: Bearer 凭据(Keycloak OIDC JWT),不是浏览器指纹风控;· 同一 URL,纯 urllib 无凭据 → 401(APISIX/3.9.1 的 401 Authorization Required);带 Bearer → 200 OK;· 所谓"唯独浏览器能 200",只是因为只有浏览器里带着登录态(含令牌)——与 TLS / HTTP2 指纹无关。· 新主通道:travel_auto_token.py(读桌面端落盘的 Bearer 令牌,纯 urllib 直连,无浏览器 / 无 CDP / 无 cookie)。9/18 版的"方案 A—E"是在"误判为风控"的前提下走过的弯路。其中浏览器品牌差异、Chrome 删除 --load-extension、App-Bound Encryption 清空 Cookie 事故等事实仍绝对成立、极具参考价值,故全文保留作为"排查过程"与"技术警示",但结论部分已按 9/26 更正重写。下文凡标注「已作废」者,均为旧结论下的推断,仅供回顾。

一、背景:这个自动化在干什么

「派猫猫旅行」是某协作平台(www.workbuddy.cn)成长中心里的一个小游戏:每天可以把一只虚拟猫"派出去旅行",到达目的地后领取积分。积分虽小,但每天 4 次巡检、到点自动完成,是个典型的"懒人自动化"需求。

自动化架构分三层(现行形态):

定时任务(每天 05:40 续期 / 08:15 / 12:30 / 16:45 / 21:00)

└─ run_travel.py 统一入口:令牌优先,失败回退 CDP

├─ travel_auto_token.py 主通道:读桌面端 Bearer 令牌,urllib 直连(无浏览器)

└─ run_travel_cdp.py 兜底通道:离屏 Edge,页面内 fetch

鉴权模型是理解整个故障的钥匙:

· 接口靠 Authorization: Bearer <accessToken> 鉴权(Keycloak OIDC JWT),不是 HttpOnly Session Cookie;

· 令牌由桌面端落盘在 %LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth\workbuddy-desktop.info(auth.accessToken,expiresIn≈55 天,桌面端运行时自动刷新;同含 auth.domain、account.uid);

· 结论:请求带上有效 Bearer 即可,纯 HTTP 库(urllib / curl)直连完全可用——"必须走浏览器"是个误判(见第三节更正)。

图 1 现行鉴权模型与架构:Bearer 令牌直连为主,浏览器通道为兜底

二、问题现象:9 月 15 日正常,9 月 16 日全 401

日期 / 时间

巡检结果

备注

09-15 12:30

state=idle,SKIP(当日额度已满)

最后一次正常:凭据有效,无 401

09-16 08:15

ERROR auth_expired / HTTP 401

凭据缺失 / 失效,未执行任何动作

09-16 12:30

ERROR auth_expired / HTTP 401

同上

现象很干净:一夜之间,所有巡检在调 status 接口时就直接 401,拿不到任何 state,自然也就没法派出、领积分。手动在浏览器里打开同一页面却一切正常——初看像"被风控认出来了,真人没事",实则是脚本侧缺失 Bearer 凭据(见第三节更正)。

三、根因分析:真因是缺 Bearer 凭据(非风控)

初稿把真因归为"9/16 平台上线 EdgeOne 风控 + Cookie 过期双因素叠加"。事后实测证明这是误判:

1. 直接死因(初判错误,已作废):初稿认为旧 travel_auto.py(urllib 带 cookie 直调)被风控封死。实测:urllib 不带 Bearer → 401;带 Bearer → 200。旧方案失败的真正原因是"只带了 Cookie、没带 Bearer",而非"被指纹风控"。

2. 导火索(部分成立):CDP 方案依赖一个有效的登录态。但这里的"登录态"核心是 Bearer 令牌,不是 Session Cookie。旧脚本既没带 Bearer、又依赖一份写死的旧 Cookie,令牌 / 会话失效即 401。

一句话更正:9/16 起的 401 是鉴权凭据缺失(缺 Bearer)所致,不是平台风控升级。所谓"urllib / curl 全 401、唯独浏览器 200",本质只是"只有浏览器带着登录态(含令牌)"。把"非浏览器 401"直接等同于"风控",是这次绕了大圈的根本原因。

图 2 故障根因更正:缺 Bearer 凭据为主因,原"风控 + Cookie 过期"降级为误判

修复方向因此简化为一条:让脚本自动拿到并带上有效 Bearer 令牌。"绕过风控""刷新 Cookie"都是南辕北辙。

四、排查过程与方案演变(含误判弯路)

本节按时间线如实记录。9/18 前的探索全部建立在"是风控"的误判上;其中技术事实(ABE、Chrome 删开关)仍成立,方案 E 的 Edge 通道作为兜底保留。

图 3 排查时间线(9/15 → 9/26 根因更正)

方案 A:--remote-debugging-port=9222 挂上已登录的 Chrome(临时方案,误判前提下)

思路:手动以调试端口启动已登录 www.workbuddy.cn 的 Chrome,自动化通过 CDP 连上去(端口 9222),复用现成会话发请求。

# 临时方案:保持这个 Chrome 一直开着,自动化去连它

chrome.exe --remote-debugging-port=9222 --user-data-dir="你的默认数据目录"

优点:改动最小,立刻能用;复用真人会话。

缺点(只能当"临时方案"):

· 必须长期开浏览器(关机即 401);Cookie 过期需手动重登;

· 现代 Chrome 自 137 起硬性拒绝在"默认 profile"上开 --remote-debugging-port,报错 DevTools remote debugging requires a non-default data directory。

结论:能救急,但把"无人值守"退化为"有人值守",且新版 Chrome 上连救急都不稳。

方案 B:专用 CDP 调试目录 + 扩展导出 Cookie(理想架构,误判前提下)

思路:脚本每次离屏自启独立调试目录的浏览器实例(非默认目录,端口能开),再把"默认 profile 里的登录态 cookie"喂给它。读明文 cookie 的关键:新版 Chromium 的 Cookie 库被 App-Bound Encryption(ABE)加密,密钥与 profile 真实路径绑定;唯一稳妥的"读明文"方式是在浏览器内部用扩展的 chrome.cookies API 读,再 POST 给本地服务,最后 CDP Storage.setCookies 注入。

默认 profile(你登录着) 专用调试目录(脚本自启、离屏)

└ 本地扩展读明文 cookie ──POST──▶ 本地接收服务 ──CDP setCookies──▶ 注入并落盘

优点:无人值守、cookie 可自动续期、扩展读取绕 ABE。

缺点(命门):强依赖 --load-extension,而 Chrome 品牌版已删此开关(见方案 E 延伸)。

结论:方向对,但把"读 cookie"当成唯一解,本质上仍是在"绕过假想的风控",没触及"缺 Bearer"的真因。

方案 C:直接 DPAPI 解密 Cookie 库(失败)

思路:跳过浏览器,直接读 Cookies 数据库,用 Local State 主密钥解密每条 cookie。

结果:主密钥能解开,但 cookie 值(v20,AES-GCM)解密时抛 InvalidTag——实际用的是 app_bound_encrypted_key,密钥与"真实 profile 路径"绑定。脚本即便指向同一物理文件,只要 Chrome 不以内核路径打开,ABE 就判定密钥不匹配。

结论:被 ABE 硬挡,现代浏览器不可用。也引出下一个危险尝试。

方案 D:junction / 符号链接伪装 profile 路径(危险,已酿成事故)

思路(事后看是坑):用 mklink /J 把默认 profile 链接成"看着像非默认"的目录,让 Chrome 以非默认目录打开——端口能开,物理上还是同一份 Cookie 库。

结果:灾难。Chrome 算出的 profile 路径是 junction 路径,与 ABE 绑定的真实路径不符,解密失败,按机制清空了整个 Cookies 库——实测把默认 profile 里所有网站的登录态全部清零(且无 Cookies.bak 备份)。本机 Chrome 一度"全员掉线"。

【警示】经验(绝对成立,与本次误判无关):任何试图用"假路径"骗过 Chromium 安全机制的方案,都会触发 ABE 的销毁逻辑,直接清零 Cookie。永远不要对默认 profile 做 junction / 软链 / 假 --user-data-dir。

方案 E(兜底通道):改用 Microsoft Edge —— 能 work,但原因不是当初想的那样

关键发现:Google Chrome 自 137 起删除了 --load-extension,且 --disable-features=DisableLoadExtensionCommandLineSwitch 变通在 142 起失效;该移除仅针对 Chrome 品牌版,Edge / Chromium / Chrome for Testing 不受影响。

初稿结论(已作废):"本机缺的不是 cookie、不是配置,而是一个能加载扩展的浏览器;装 Edge 即彻底解决风控。"

更正:Edge 通道之所以能 200,不是因为它"绕过了风控指纹",而是因为它运行在真实浏览器里、自然带着登录态(含 Bearer 令牌)。它只是"带令牌的浏览器"这个事实的被动受益者,而非"破解了风控"。它仍有价值——作为令牌通道失败时的兜底(见第八节),但链路长、依赖 Edge 登录态与扩展导出,并非首选。

五、各方案对比一览

方案

无人值守

是否解决真因(缺 Bearer)

主要代价 / 风险

结论

A. 挂已登录 Chrome(端口常开)

否,需长期开浏览器

否(靠浏览器带令牌)

占资源、易断;新版 Chrome 默认 profile 端口被拒

仅救急

B. 专用 CDP 目录 + 扩展导出

是

否(仍绕 cookie,未触 Bearer)

依赖 --load-extension

误判下的探索

C. DPAPI 直接解密

是(理论)

否

被 ABE 拦截

不可行

D. junction 伪装路径

—

—

清空全部 Cookie,不可逆

严禁

E. 改用 Edge(CDP 兜底)

是

被动(浏览器带令牌)

多装浏览器;依赖 Edge 登录态,未登录即失效

兜底通道

F. Bearer 令牌直连(最终主通道)

是

是

需桌面端运行以自动刷新令牌

最终采用

六、最终方案与部署要点(按 9/26 更正重写)

落地形态(现行):

· 主通道:4 次巡检(08:15 / 12:30 / 16:45 / 21:00)+ 1 次续期(05:40)统一走 run_travel.py → travel_auto_token.py——读桌面端 Bearer 令牌,纯 urllib 直连,无浏览器 / 无 CDP / 无 cookie;

· 兜底:令牌缺失 / 过期 / 被拒(退出码非 0)时,自动回退 run_travel_cdp.py --browser edge(离屏 Edge,页面内 fetch);

· 健壮性加固:401 自愈关闭实例时,改用 CDP Browser.close + 按 --user-data-dir 精确匹配,不再按进程名全杀浏览器(避免误伤正在用的 Edge 窗口)。

唯一前提:Bearer 令牌由桌面端维护,需保持桌面端运行以自动刷新(令牌 ≈55 天,但到期前桌面端需在线刷新)。掉线时回退 Edge 兜底;若 Edge 也未登录则需补登一次。

图 4 现行方案:run_travel.py 令牌优先 + Edge CDP 兜底

七、经验与启示

0.(最重要)"脚本 401、手动正常"先确认是「缺凭据」还是「真风控」。本文初稿把"非浏览器客户端 401"直接归为风控,结果绕了大圈。实测同一 URL:无 Bearer → 401,有 Bearer → 200,真相是缺鉴权而非指纹。先抓包看响应(是 401 Authorization Required 还是风控挑战页)再下结论。

1. Cookie / 令牌类自动化要把"取凭据"和"执行业务"解耦。前者(续期)和后者(巡检)分开调度,才能做到无人值守。

2. 浏览器品牌差异是真实陷阱(在"需要读浏览器内 Cookie"的兜底场景下仍成立)。Chrome 品牌版自 137 删 --load-extension、142 起变通失效;Edge / Chromium / Chrome for Testing 不受影响。

3. App-Bound Encryption 极其危险(与本次误判无关,绝对成立)。其"路径不符即清空 Cookie"机制,意味着任何 junction / 符号链接 / 假 --user-data-dir 伪装都会直接清零登录态、且无备份。永远用真实 profile 路径启动浏览器。

4. "让浏览器自己发请求"是兜底的备选,不是首选。当带凭据的纯 HTTP 调用就能 200 时,优先用纯 HTTP,把浏览器留给真正需要它的场景——既轻量又稳。

八、9/26 更正后实测复盘(真实运行数据)

以下摘自 travel_auto.log,用于验证更正后的方案并诚实暴露残留问题:

· 9/26 00:09 首次切令牌通道:AUTH token exp=2026-11-20(剩余 55.0 天),STATUS state=traveling——200,鉴权链路恢复;

· 9/26 08:15 起四轮(08:15 / 12:30 / 16:45 / 21:00)令牌通道稳定成功:DEPART 成功(健身房)、CLAIM 成功 +9、SKIP 今日已达上限 均正常;

· 9/26—9/27 全天:除 05:41 那一轮外,各轮均 channel=token 且 200(travel_state.json 末次 09-27 21:01 channel=token,正常 SKIP);

【注意】残留问题(诚实记录):每天 05:41 紧接 05:40 续期后的那一轮自动化偶发 401。日志显示该轮先走令牌通道失败、回退 CDP 兜底也因 "CDP profile 未登录 www.workbuddy.cn" 而 401(9/26、9/27、9/28 的 05:41 均如此)。推测根因:05:41 时刻桌面端令牌文件尚未就绪(令牌通道先失败),而 Edge 兜底 profile 近期未登录,故漏跑。(该轮常因额度 / 状态无需动作,业务影响小,但属待优化点,标注为"推测 / 待核")。

结论:主通道(Bearer)稳定可信;CDP 兜底在 Edge 未登录时形同虚设。建议:保持 Edge 默认 profile 登录,或把 05:41 巡检延后至桌面端令牌刷新完成之后。

附录:关键判断命令(备查)

# 0) 验证是"缺 Bearer"还是"真风控"(本次更正的关键判据)

# curl -i https://www.workbuddy.cn/activity/growth/buddy/travel/status

# → 无头 401 Authorization Required(APISIX)

# curl -i -H "Authorization: Bearer <token>" 同一 URL → 200

# token 取自 %LOCALAPPDATA%\CodeBuddyExtension\Data\Public\auth\workbuddy-desktop.info

# 带 Bearer 仍 401 → 才是真风控 / 令牌失效;带 Bearer 200 → 真因是缺凭据

# 1) 验证某浏览器是否仍支持 --load-extension

# 临时 profile 启动 + 开 CDP 端口,查 Target.getTargets 是否出现 chrome-extension://<id>/sw.js

# Edge 153 出现;Chrome 153 不出现(仅内置组件扩展)

# 2) 验证默认 profile 能否开调试端口

# Chrome 153 报错:DevTools remote debugging requires a non-default data directory

# 专用(非默认)目录则可正常监听 9222

# 3) 读 Cookie 库过期时间(Chrome/Edge 通用,无需解密)

# Cookies 库:<User Data>/Default/Network/Cookies

# expires_utc 为 1601-01-01 起微秒;>0 为到期时间,=0 为 SESSION

本文所涉排查均在本机隔离环境内完成,未对平台做任何异常访问;所有 cookie 读取均在本地浏览器进程内、经用户已授权的扩展完成。Bearer 令牌仅从本机桌面端落盘的凭据文件读取,不外传。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档