逆向工程 GraphQL persistedQuery 扩展
GraphQL 是一种查询语言,用于从网站后端获取深度嵌套的结构化数据,类似于 MongoDB 查询。
请求通常是对某个通用 /graphql 端点的 POST,其正文如下:
但是,对于大型数据结构,这会变得低效 - 您在 POST 请求正文中发送大型查询,这(几乎总是)相同,并且仅在网站更新时发生变化; POST请求无法被缓存等。因此,开发了一个名为“持久查询”的扩展。这不是一个反抓取的秘密;而是一个秘密。您可以在此处阅读有关它的公共文档。
TLDR:客户端计算查询文本的 sha256 哈希值并仅发送该哈希值。此外,您可以将所有这些内容放入 GET 请求的查询字符串中,使其易于缓存。以下是来自 Zillow 的请求示例
如您所见,它只是有关 persistedQuery 扩展的一些元数据、查询的哈希值以及要嵌入查询中的变量。
这是来自 expedia.com 的另一个请求,以 POST 形式发送,但扩展名相同:
这主要优化了网站性能,但它给网页抓取带来了一些挑战:
- GET 请求通常更容易被阻止。
- 隐藏查询参数:我们不知道完整的查询,因此如果网站响应“未找到持久查询”错误(要求我们发送完整的查询,而不仅仅是哈希值),我们无法发送。
- 一旦网站发生了一点点变化,客户端开始请求新的查询 - 即使旧的查询可能仍然有效,服务器很快就会忘记它的 ID/散列,并且您使用此散列的请求将永远不会工作再次强调,因为您无法“提醒”服务器完整的查询文本。
因此,由于不同的原因,您可能会发现自己需要提取整个查询文本。您可以深入研究网站 JavaScript,如果幸运的话,您可能会在那里找到完整的查询文本,但通常,它是以某种方式从多个片段等动态构建的。
因此,我们想出了一个更好的方法:我们根本不碰客户端 JavaScript。相反,我们将尝试模拟客户端尝试使用服务器不知道的哈希的情况。因此,我们需要拦截浏览器发送的(有效)请求,并将哈希值修改为伪造的,然后再将其传递给服务器。
对于这个用例,存在一个完美的工具:mitmproxy,一个开源 Python 库,它可以拦截您自己的设备、网站或应用程序发出的请求,并允许您使用简单的 Python 脚本对其进行修改。
下载 mitmproxy,并准备一个 Python 脚本,如下所示:
import json def request(flow): try: dat = json.loads(flow.request.text) dat[0]["extensions"]["persistedQuery"]["sha256Hash"] = "0d9e" # any bogus hex string here flow.request.text = json.dumps(dat) except: pass
这定义了 mitmproxy 将在每个请求上运行的钩子:它尝试加载请求的 JSON 主体,将哈希修改为任意值,并将更新的 JSON 写入作为请求的新主体。
我们还需要确保将浏览器请求重新路由到 mitmproxy。为此,我们将使用名为 FoxyProxy 的浏览器扩展。它在 Firefox 和 Chrome 中均可用。
只需添加具有以下设置的路线:
现在我们可以使用以下脚本运行 mitmproxy:mitmweb -s script.py
这将打开一个浏览器选项卡,您可以在其中实时观看所有拦截的请求。
如果您转到特定路径并查看请求部分中的查询,您将看到一些垃圾值已替换了哈希值。
现在,如果您访问 Zillow 并打开我们尝试用于扩展的特定路径,然后转到响应部分,客户端会收到 PersistedQueryNotFound 错误。
Zillow 前端的反应是将整个查询作为 POST 请求发送。
我们直接从此 POST 请求中提取查询和哈希。为了确保 Zillow 服务器不会忘记此哈希,我们定期使用完全相同的查询和哈希运行此 POST 请求。这将确保即使服务器的缓存被清理或重置或网站发生更改,抓取工具也能继续工作。
结论
持久查询是 GraphQL API 的强大优化工具,通过最小化负载大小和启用 GET 请求缓存来增强网站性能。然而,它们也给网络抓取带来了重大挑战,主要是由于对服务器存储的哈希值的依赖以及这些哈希值可能无效的可能性。
使用 mitmproxy 拦截和操作 GraphQL 请求提供了一种有效的方法来显示完整的查询文本,而无需深入研究复杂的客户端 JavaScript。通过强制服务器响应 PersistedQueryNotFound 错误,我们可以捕获完整的查询负载并将其用于抓取目的。定期运行提取的查询可确保抓取器保持功能,即使发生服务器端缓存重置或网站发展也是如此。
以上是逆向工程 GraphQL persistedQuery 扩展的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

Python和JavaScript在开发环境上的选择都很重要。1)Python的开发环境包括PyCharm、JupyterNotebook和Anaconda,适合数据科学和快速原型开发。2)JavaScript的开发环境包括Node.js、VSCode和Webpack,适用于前端和后端开发。根据项目需求选择合适的工具可以提高开发效率和项目成功率。
