4.5 KiB
4.5 KiB
CF-1 Cloudflare 验证处理(调研)
1. 复现(2026-09-30,HTTP 5 次、浏览器 5 次,间隔 ≥15s)
| 请求 | 结果 |
|---|---|
| HTTP(Deno,Firefox UA)观众 / 憨憨搜索页,无 Cookie、仅 cf_clearance、补齐浏览器请求头 | 全部 302 → login.php(server: cloudflare,无 cf-mitigated):没被挑战 |
| 浏览器,观众账号 profile(已有 cf_clearance)搜索页 | 200,直接出结果 |
| 浏览器,全新 profile:憨憨 | 无挑战、无 CF Cookie |
| 浏览器,全新 profile:观众 ×2 | 首次导航 403(挑战),1–5 秒内不点即过,拿到 cf_clearance(Cookie 期限 1 年;真实有效期由站点 Challenge Passage 决定,不可见) |
结论:观众有 CF 挑战(非交互 managed/JS 类,挑战页类型未抓到),固定 Windows 身份的 camofox 能自动通过;憨憨未见。
关键发现:两端出口不一致。cdn-cgi/trace:浏览器(站点未开代理 → 直连)出口 HKG;app 的 HTTP 端走 globalThis.fetch,而 Deno 会读容器的 HTTPS_PROXY(override 里的 mihomo 中继)→ 出口 DFW。BR-4 §11.5 的"按站点统一出口"在 HTTP 侧没生效;代理换节点也是"随机出 CF"的可能来源。
分类缺陷:HTTP 遇挑战(403)在 spider fetchPage 被归为 auth_invalid → 账号标失效、开"登录失效"事项、触发重登;503 挑战被归为维护。
2. 试验:浏览器 cf_clearance + 同 UA 给 HTTP
HTTP 本身未被挑战,带不带 cf_clearance 都是 302,本次无法判定。另因出口不同(HKG vs DFW),即使被挑战也不满足"同 IP"前提。MP 的 HTTP 端是 requests/httpx(非浏览器 TLS),照样复用浏览器取得的 cookie+UA,说明多数 PT 站实际只绑 UA+IP。把"首次复用重试"本身作为在线验证,按站点记结果。
3. 方案对比
| 成功率 | 请求成本 | 礼貌 | 改动 | 与 BR-4 | |
|---|---|---|---|---|---|
| A 同步 cf_clearance+UA,HTTP 重试 1 次 | 取决于站点是否绑 TLS | 最低 | 好 | 小 | 需改"仅浏览器"规则 |
| B 该请求改由浏览器执行 + N 小时走浏览器标记 | 高 | 中(整页加载) | 好 | 中 | 一致 |
| C 站点长期全走浏览器 | 高 | 高 | 一般 | 中 | 一致 |
| D FlareSolverr | 与 camofox 相当 | 多一容器 | — | 大 | 不需要(用户否决) |
推荐 A→B 级联(照 MP,camofox 即仿真浏览器):
- 触发:
http.ts识别cf-mitigated: challenge或 403/503 +underChallenge(html)→ 新错误SiteError("challenge");不再算凭据错误。 - 过挑战:用该账号 profile 开浏览器会话打开同一 URL。① 等自动通过(≤15s,轮询标题 / cf_clearance);② 未过 →
browser.solve_challenge视觉子流程,只允许"我是人类"复选框 / Turnstile 单步点击,maxSteps 小、最多 1–2 次;③ 图片选择 / 输码类 → 会话转waiting(challenge_unsolved),生成待处理事项"观众需要你在原站视图里过一次验证",用户在桌面(同一会话)过完,交还即继续。约束:只处理用户已登录账号的站点;同站单次触发只处理一次,30 分钟节流;不接打码服务。 - 同步:读回 cf_clearance +
navigator.userAgent,前提是账号 UA 来源 = browser 且两端出口相同;HTTP 重试 1 次。 - 回退:仍被挑战 → 本次请求改为浏览器导航取
outerHTML交给现有解析器;站点记browserMode6 小时(续期 / 到期再试 HTTP);记cfReuse = fails,以后跳过第 3 步。 - 展示:站点页显示"Cloudflare:浏览器代理中,至 hh:mm / 需人工验证 / 复用有效"。
4. 实现清单
packages/adapters/src/sites/{http.ts,types.ts,spider/adapter.ts}:challenge错误类,修 403 误判。sources-identity/runtime.ts:非代理站点显式Deno.createHttpClient({proxy:null})直连(或浏览器也按 env 代理),两端同出口;siteFetch挂挑战钩子(重试 / 浏览器执行)。service/credentials.ts、browser/cookies.ts:splitBrowserOnlyCookies改为"同 UA 同出口时 cf_clearance 进 HTTP Cookie",__cf_bm仍不带。site.config.cloudflare = {browserUntil, cfReuse, lastChallengeAt, lastSolvedBy};snapshot.ts不再对 challenge 调onAuthError。browser/service.ts:新增fetchViaBrowser(siteId, url)(profile 锁、限流令牌、site_disabled检查);enterWaiting/ 待处理事项、桌面接管(WT-1)、BR-3 重连沿用。agent/challenge.ts:无父 Agent 时由系统发起子流程(预算来自设置);Turnstile 在跨域 iframe,click_at需插件提供真实鼠标坐标点击。- 测试:挑战分类、级联状态机、出口一致。