news 2026/5/7 17:44:09

逆向工程ChatGPT Web API:从网络协议到反爬机制的实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
逆向工程ChatGPT Web API:从网络协议到反爬机制的实战解析

1. 项目概述:一次逆向工程ChatGPT Web API的实战记录

最近在GitHub上看到一个挺有意思的项目,叫gin337/ChatGPTReversed。这本质上是一个教育性质的项目,核心目标不是提供一个现成的、稳定的“免费API”,而是通过一个具体的案例——逆向分析ChatGPT网页版的通信流程,来学习如何应对现代复杂Web应用的反爬与安全机制。对于前端开发者、安全研究员或者对网络协议感兴趣的朋友来说,这个过程本身的价值远超于最终得到的那个“调用工具”。我自己也花了不少时间,沿着作者的思路重新走了一遍,并补充了大量在真实逆向过程中会遇到的具体问题和解决方案。这篇文章,我就来详细拆解一下这个“学习之旅”,从打开浏览器开发者工具开始,到最终理解整个认证与通信链路的来龙去脉。

这个项目适合谁呢?首先,你需要对JavaScript和网络协议(HTTP/HTTPS)有基本了解。其次,最好有过使用浏览器开发者工具(特别是Network和Sources面板)的经验。如果你对“前端如何与后端交互”、“现代Web应用如何防御自动化脚本”这些问题感到好奇,那么这个过程会给你很多启发。我们将完全站在技术学习的角度,使用公开的、合法的开发者工具,来分析一个公开的Web应用的通信模式,这是理解和学习Web技术栈的常规方法。

2. 核心思路与技术挑战拆解

2.1 逆向工程的目标与边界

逆向工程ChatGPT网页版,我们的目标不是破解或绕过其核心服务逻辑,而是理解其客户端(浏览器)与服务器(OpenAI后端)之间的数据交换协议。这包括:

  1. 会话建立:用户登录后,如何维持一个有效的会话状态。
  2. 请求鉴权:每个向对话接口发送的请求,需要携带哪些认证和防伪令牌。
  3. 动态挑战:服务器如何通过动态生成的挑战(如Proof of Work)来增加自动化调用的成本。
  4. 数据流:对话消息是如何以流式(EventStream)形式返回的。

理解这些,能帮助我们深刻认识到一个成熟的、高并发的AI服务在前端安全设计上的复杂性。这远比简单地调用一个官方API SDK要复杂得多,因为你需要处理所有本应由浏览器和官方前端代码自动完成的事情。

2.2 面临的主要技术壁垒

OpenAI在前端部署了多层防御,这在逆向过程中会逐一显现:

  • 令牌系统:多种令牌(JWT, CSRF, Session, Requirements, Proof)交织在一起,各有其生命周期和作用域。它们并非一次性获取,而是在不同阶段动态生成和验证。
  • 反自动化机制:这是最有趣的部分。项目资料中提到的proofofwork(工作量证明)就是典型例子。它要求客户端根据服务器下发的seed(种子)和difficulty(难度),利用本地计算资源找到一个符合特定条件的哈希值。这直接增加了脚本批量调用的时间和计算成本。
  • 请求链依赖:请求之间存在严格的顺序依赖。例如,你必须先拿到A令牌,才能去B接口换取C令牌,最后用C令牌加上计算出的D令牌,才能发起真正的对话请求。任何一个环节失败,整个链条都会中断。
  • 代码混淆与压缩:前端JavaScript代码是经过压缩和混淆的,变量名通常是单个字母,函数调用链难以直接阅读。这要求我们具备在混淆代码中设置断点、跟踪调用栈的能力。

3. 实操环境准备与工具链

3.1 核心工具:浏览器开发者工具

这是我们唯一的“主力武器”。不需要任何特殊的抓包软件,现代浏览器(Chrome/Edge/Firefox)内置的DevTools就足够了。关键面板如下:

  • Network(网络):记录所有HTTP请求和响应。这是我们的“地图”,所有客户端与服务器的交互都一览无余。务必勾选“Preserve log”(保留日志)并禁用缓存,以防请求记录被刷新掉。
  • Sources(源代码):用于查看、调试前端JavaScript代码。即使代码被压缩,我们也可以通过设置断点、观察调用堆栈(Call Stack)和监控变量(Watch)来理解其逻辑。
  • Application(应用):查看和操作本地存储(Local Storage, Session Storage)、Cookies。很多令牌信息就存储在这里。

3.2 辅助分析与调试技巧

面对混淆的代码,直接阅读是低效的。我常用的策略是:

  1. 关键词搜索:在Sources面板的代码文件中,搜索一些可能未被混淆的关键字符串,如backend-apichat-requirementsgetRequirementsToken等。这能快速定位到相关代码块。
  2. XHR/Fetch断点:在Sources面板的“XHR/Fetch Breakpoints”中,可以添加针对特定URL(如包含conversation的请求)的断点。当浏览器发起该请求时,代码执行会自动暂停,此时你就能在调用栈中看到是哪个函数发起了这个请求,从而逆向追踪。
  3. 事件监听器断点:在Sources面板的“Event Listener Breakpoints”中,可以勾选“Script”下的“Script First Statement”,这会在脚本开始执行时断住,有助于跟踪页面初始化流程。

注意:整个分析过程应在ChatGPT的官方网页端进行。请确保你的所有操作都遵守该网站的使用条款,仅用于个人学习和技术研究,不要进行高频、自动化的请求,以免对服务造成影响或触发风控。

4. 逐步逆向:从页面加载到发送消息

现在,我们按照一次完整的“用户发送消息”流程,来拆解每个步骤。

4.1 第一步:会话初始化与基础令牌获取

打开ChatGPT网页并登录后,第一个需要关注的是会话状态。清空Network记录,然后刷新页面。

  1. 获取CSRF令牌:通常,你会先看到一个指向/api/auth/csrf的请求。这是一个GET请求,服务器会返回一个csrfToken。CSRF(跨站请求伪造)令牌是Web安全中常见的手段,用于确保请求来源于你自己的页面。这个令牌通常需要在后续的、可能修改服务器状态的POST请求的Header或Body中携带。
  2. 获取会话令牌:紧接着,一个到/api/auth/session的请求会被发出。这个请求的响应里就包含了核心的accessToken。这是一个JWT(JSON Web Token),它是你已登录身份的凭证,相当于你进入服务大门的“长期通行证”。在Network面板中查看这个请求的响应体,类似这样:
    { "user": {...}, "expires": "...", "accessToken": "eyJhbGciOiJ...很长的一串字符", "authProvider": "..." }
    这个accessToken需要被妥善保存,并在后续几乎所有与后端交互的请求的Authorization请求头中使用,格式为:Authorization: Bearer eyJhbGciOiJ...

4.2 第二步:解密动态挑战请求链

这是整个逆向过程中最精妙也最复杂的一环。当你准备发送第一条消息时,真正的挑战才开始。

  1. 定位对话请求:在输入框发送一条消息(例如“Hello”)。在Network面板中,你会找到一个关键的POST请求,其URL类似于/backend-api/conversation。它的响应类型(Type)是eventsource,这意味着服务器是以流式(Server-Sent Events)返回AI的回复。

  2. 分析请求头与载荷:点击这个conversation请求,查看它的“Headers”和“Payload”。你会发现,除了Authorization头,还有一堆其他的令牌:

    • csrf-token: 来自第一步。
    • requirements-token: 一个看起来像哈希值的字符串。
    • proof-token: 另一个哈希值字符串。 显然,在发起对话请求前,浏览器已经准备好了这些“材料”。
  3. 逆向chat-requirements接口:在conversation请求之前,通常存在一个到/backend-api/sentinel/chat-requirements的POST请求。这个接口就是动态挑战的核心。它的请求体可能很简单,甚至为空,但它的响应至关重要。正如项目资料所示,响应体包含了挑战的详细信息:

    { "persona": "chatgpt-freeaccount", "token": "y", // 这就是 Required Requirements Token "arkose": {}, // 可能用于处理更复杂的验证码 "turnstile": {}, // 可能用于Cloudflare Turnstile验证 "proofofwork": { "required": true, "seed": "0.81186133b2821174", // 计算Proof Token的种子 "difficulty": "073682" // 计算难度 } }

    服务器在这里说:“想要发起对话吗?先给我解决这个小难题。”它返回了一个新的令牌ytoken字段),以及一个工作量证明的挑战(seeddifficulty)。

  4. 追踪令牌生成函数:现在的问题是,chat-requirements接口的请求头里,那个requirements-token(我们称之为x)是从哪来的?根据项目作者的发现,它来自前端代码中的一个函数getRequirementsToken()。我们需要在Sources面板中找到它。

    • 在Sources面板中,按Ctrl+Shift+F(Windows)或Cmd+Opt+F(Mac)进行全局搜索,输入getRequirementsToken
    • 在压缩的代码中找到这个函数,并在其函数体内部或调用它的地方打上断点(点击行号)。
    • 回到页面,再次尝试发送消息。代码执行会在断点处暂停。
    • 这时,你可以使用右侧的“Scope”或“Watch”面板,查看当前作用域内的变量。逐步执行(F10),观察函数的返回值,你就能捕获到生成的requirements-tokenx)。

4.3 第三步:破解工作量证明(Proof of Work)

拿到了挑战参数(seeddifficulty),下一步就是生成proof-tokenz)。这个过程发生在_generateAnswer函数中。

  1. 理解计算逻辑:这个函数的核心是一个哈希计算。它通常会将seed、以及一些从getConfig()函数获取的浏览器环境指纹(如用户代理、屏幕分辨率、时区、CPU核心数、内存等)拼接起来,然后进行哈希运算(很可能是SHA-256)。
  2. 满足难度条件:计算出的哈希值需要满足特定条件,例如哈希值的前N位十六进制数字必须为0,这里的N由difficulty决定。difficulty: “073682”可能意味着哈希值需要以一定数量的零开头,或者满足其他算术条件。
  3. 暴力搜索:为了找到满足条件的哈希,函数会进行一个循环(可能递增一个nonce值),不断计算新的哈希,直到找到符合条件的那个。如果尝试一定次数后仍未找到,它可能会返回一个降级的默认值(fallback)。
  4. 调试获取结果:和追踪getRequirementsToken一样,在_generateAnswer函数内部或返回处设置断点。当代码暂停时,观察其返回值,这就是我们需要的proof-tokenz)。

实操心得:在实际调试中,你可能会发现_generateAnswer的计算非常耗时,甚至会导致浏览器页面“卡住”。这是因为前端的JavaScript正在全力进行哈希计算。这恰恰证明了PoW机制的有效性——它让自动化脚本的每次请求都必须付出可观的计算成本。在真实逆向编写代码时,我们需要用Node.js或其他后端语言重新实现这个哈希计算逻辑,效率会高很多。

4.4 第四步:组装最终请求

至此,我们集齐了所有“龙珠”:

  • AuthorizationBearer+ 从/api/auth/session获取的accessToken
  • csrf-token:从/api/auth/csrf获取。
  • requirements-token:由前端函数getRequirementsToken()动态生成(x)。
  • proof-token:由前端函数_generateAnswer()根据服务器下发的seeddifficulty计算得出(z)。

此外,/backend-api/sentinel/chat-requirements接口返回的token字段(y),很可能需要作为请求体(Payload)的一部分,在调用/backend-api/conversation时发送回去。

现在,我们可以手动构建一个与浏览器行为一致的POST请求到/backend-api/conversation。请求体应包含对话消息、模型参数等,并且设置Accept: text/event-stream来接收流式响应。如果一切正确,你将能接收到和网页上一样的、逐字蹦出的AI回复数据流。

5. 从分析到实现:构建Node.js客户端的关键点

理解了原理,将其转化为一个可运行的Node.js项目(如ChatGPTReversed)时,需要注意以下核心实现:

5.1 令牌管理与会话保持

你需要一个Session类来管理所有令牌的生命周期。

  • accessToken(JWT)通常有效期较长,但需要处理过期刷新(虽然网页端可能通过静默重定向刷新)。
  • csrfToken可能在每次会话或一定时间后失效。
  • requirementsTokenproofToken是针对单次chat-requirements请求的,每次获取新的挑战都需要重新生成。

一个稳健的实现应该能自动处理令牌的获取、缓存和刷新逻辑。

5.2 重新实现前端哈希逻辑

这是项目的技术核心。你需要:

  1. 提取环境参数:分析getConfig()函数,确定它收集了哪些浏览器指纹。在Node.js中,你需要模拟一组合理的、固定的值,或者提供一个接口让使用者可以自定义这些指纹。
  2. 实现哈希函数:确定前端使用的哈希库(如hash-wasm)和具体算法(如SHA-256)。在Node.js中,可以使用内置的crypto模块来实现。
  3. 实现PoW求解器:根据seeddifficulty和模拟的指纹,编写一个循环,不断变更某个变量(如nonce),计算哈希,并检查是否满足难度条件。这里是一个极度简化的概念示例:
const crypto = require('crypto'); function generateProofToken(seed, difficulty, browserFingerprint) { let nonce = 0; const maxAttempts = 1000000; // 防止无限循环 const targetPrefix = '0'.repeat(parseInt(difficulty, 10)); // 假设难度表示前导零的个数 while (nonce < maxAttempts) { const inputString = `${seed}|${browserFingerprint}|${nonce}`; const hash = crypto.createHash('sha256').update(inputString).digest('hex'); if (hash.startsWith(targetPrefix)) { return hash; // 这就是 proof-token (z) } nonce++; } // 达到尝试次数后,返回一个降级值(需根据前端反编译确定) return 'fallback_proof_token'; }

重要提示:上述代码仅为逻辑演示。真实的difficulty解析、指纹拼接方式、降级逻辑必须通过精确的反编译前端代码来确定,否则无法生成服务器接受的正确令牌。

5.3 处理流式响应(EventStream)

/backend-api/conversation接口返回的是text/event-stream格式。在Node.js中,你不能像处理普通JSON那样直接解析响应体。你需要监听data事件,并对接收到的数据进行按行分割、识别data:前缀等处理,才能提取出有效的对话内容。许多库(如eventsource-parser)可以简化这个过程。

6. 常见问题、排查技巧与伦理思考

6.1 逆向过程中常见问题

问题现象可能原因排查思路
chat-requirements接口返回403/4xx错误requirements-token无效或缺失;请求头不完整;IP或会话异常。1. 检查getRequirementsToken函数是否被正确调用和模拟。
2. 确保请求包含了所有必要的Header(如Authorization,csrf-token)。
3. 尝试使用全新的浏览器会话(无痕模式)重新开始。
conversation接口返回错误,提示令牌无效proof-token计算错误;requirements-token已过期;accessToken失效。1.重点检查PoW计算:确认seeddifficulty、指纹参数的拼接顺序和哈希算法与前端完全一致。使用调试时捕获的真实seed和结果来验证你的算法。
2. 确保在获取proof-token后立即使用,令牌可能有过期时间。
3. 重新获取accessToken
接收不到流式响应,或响应格式错误EventStream解析逻辑有误;网络连接中断。1. 使用原始的HTTP客户端(如node-fetch)并检查响应头Content-Type: text/event-stream
2. 逐字节打印原始响应数据,与浏览器Network面板中看到的原始流进行对比,确保解析逻辑能正确分割事件。
代码被更新,原有函数名或流程改变OpenAI前端部署了新版本。这是逆向项目最大的不稳定性来源。需要重新进行步骤2和3的分析,定位新的函数名和接口参数。关注项目GitHub仓库的Issue和更新,社区通常会快速讨论新变化。

6.2 一些重要的实操心得

  1. 环境一致性是关键:浏览器指纹(User-Agent, Viewport, Timezone等)在令牌生成中可能被使用。在Node.js中模拟时,最好从一次真实的浏览器会话中捕获这些值并固定使用,而不是随机生成。
  2. 不要高频请求:即使是出于学习目的的逆向,也应严格控制请求频率。PoW机制本身就是反自动化的,频繁请求极易触发更严格的风控(如IP封禁、要求验证码等),导致学习过程中断。
  3. 理解重于复制:这个项目的终极价值在于学习逆向工程的思路和方法论(如何抓包、如何下断点、如何跟踪调用栈、如何分析混淆代码),而不是得到一个永久可用的“免费API”。前端防御策略会持续演进,具体的令牌生成算法可能会变,但解决问题的基本技能是通用的。
  4. 关注法律与条款:所有分析应仅限于公开的、客户端层面的网络交互。尊重知识产权,不要试图解密或分发服务器端的核心模型或私有代码。你的行为应始终符合ChatGPT网站的服务条款。

6.3 关于此类项目的伦理思考

从事这类教育性逆向项目,必须时刻保持清晰的边界。我们学习的对象是“公开的客户端-服务器通信协议”,这与攻击服务器、窃取数据有本质区别。整个过程应使用合法的开发者工具,在公开的Web界面上进行。学习的目的是提升自身对Web安全、协议设计和大型应用架构的理解,而非寻找系统的漏洞或进行滥用。将所学知识用于构建更安全的自家产品,或是进行更深入的安全研究(在合法授权范围内),才是技术成长的正确方向。

通过这样一次完整的逆向之旅,你收获的将不仅仅是如何调用一个接口,而是一整套应对复杂、动态、强防御型Web系统的分析方法和实战经验。这种能力,在当今的Web开发和安全领域,是非常宝贵的。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/7 17:44:09

5分钟掌握WaveTools:解锁《鸣潮》120FPS帧率的终极指南

5分钟掌握WaveTools&#xff1a;解锁《鸣潮》120FPS帧率的终极指南 【免费下载链接】WaveTools &#x1f9f0;鸣潮工具箱 项目地址: https://gitcode.com/gh_mirrors/wa/WaveTools WaveTools是一款专为《鸣潮》玩家设计的开源工具箱&#xff0c;能够轻松解锁游戏帧率限制…

作者头像 李华
网站建设 2026/5/7 17:41:00

TIDAL无损音乐下载终极指南:24-bit/192kHz母带级音质免费保存

TIDAL无损音乐下载终极指南&#xff1a;24-bit/192kHz母带级音质免费保存 【免费下载链接】tidal-dl-ng TIDAL Media Downloader Next Generation! Up to HiRes / TIDAL MAX 24-bit, 192 kHz. 项目地址: https://gitcode.com/gh_mirrors/ti/tidal-dl-ng 你是否曾经为TID…

作者头像 李华
网站建设 2026/5/7 17:37:43

数据库概念结构设计完全指南:从E-R图到建表实战

前言&#xff1a;为什么需要概念结构设计&#xff1f;在数据库系统的开发过程中&#xff0c;设计者通常需要面对一个问题&#xff1a;如何将现实世界中的业务需求准确、高效地转化为计算机能够存储和处理的数据结构&#xff1f;如果直接跳到物理设计&#xff08;也就是写CREATE…

作者头像 李华
网站建设 2026/5/7 17:37:40

对比直接使用厂商API体验Taotoken在路由与容灾上的便利性

使用 Taotoken 平台简化大模型 API 接入与运维 1. 从单一厂商到聚合平台的转变 在早期的大模型应用开发中&#xff0c;我们通常直接对接单一厂商的 API 端点。这种方式虽然直接&#xff0c;但在实际运维中面临诸多挑战。每次需要切换模型供应商时&#xff0c;都需要修改代码中…

作者头像 李华