公众号旧文

JS challenge 到底在 challenge 什么?

作者:胖子阅读 —

之前胖子在使用 yt-dlp 时,看到过类似这样的提示:

图片

“JS challenge failed”

“无法通过 JavaScript challenge”

“部分格式未获取”

C:\Users>yt-dlp https://www.youtube.com/watch?v=QwbU-0BVcms
[youtube] Extracting URL: https://www.youtube.com/watch?v=QwbU-0BVcms
[youtube] QwbU-0BVcms: Downloading webpage
WARNING:
[youtube] No supported JavaScript runtime could be found.
  Only deno is enabled by default;
  to use another runtime add
  --js-runtimes RUNTIME[:PATH]
  to your command/config.
  YouTube extraction without a JS runtime has been deprecated,
  and some formats may be missing.
  See https://github.com/yt-dlp/yt-dlp/wiki/EJS
  for details on installing one

我很好奇 JS challenge 到底在 challenge 什么?

可能很多人的直觉是:

网站给出一道 JavaScript 题,让客户端计算出答案,然后服务器验证答案是否正确。

但实际情况完全不是这样。

JS challenge 表面上是在算题,本质上是在判断:

访问网站的到底是一个真实浏览器,还是自动化程序。

一、JS challenge 的基本流程

当浏览器访问某些网站时,服务器不会立刻返回真正的网页,而是先返回一段 JavaScript 代码。

浏览器需要:

  1. 下载这段 JavaScript
  2. 执行代码
  3. 生成一个 token 或 cookie
  4. 再次请求页面

服务器验证通过之后,才会返回真正的内容。

整个过程通常只需要几十毫秒,用户几乎感觉不到。

但如果访问者是:

  • curl
  • wget
  • 简单爬虫
  • 某些下载工具

这些程序通常不会执行 JavaScript,于是 challenge 就会失败。

二、为什么要这样做

网站这样做的目的主要有两个:

第一,阻挡爬虫。 第二,减少自动化攻击。

很多网站每天都会遇到大量自动化请求,例如:

  • 爬取数据
  • 批量注册
  • 暴力登录
  • 抢购脚本

如果服务器直接返回网页,这些程序就可以很轻松地获取数据。

JS challenge 的作用,就是在访问入口增加一个过滤器。

只有能够正常执行 JavaScript 的环境,才会被认为是比较可信的访问者。

三、为什么看起来只是“算一道数学题”

很多 JS challenge 的代码里,会出现一些类似这样的计算:

var a = 37
var b = 19
var c = (a * b + 17) % 97

看起来好像只是一个简单的数学题。

但实际上,这些计算只是外壳。

在这些计算的过程中,脚本通常会顺便读取很多浏览器信息,例如:

浏览器类型 操作系统 屏幕分辨率 时区 字体 WebGL 信息 Canvas 指纹

这些信息组合起来,可以形成一种叫做浏览器指纹的特征。

服务器并不是单纯验证数学结果,而是在判断:

这些数据看起来是否像一个真实浏览器生成的。

四、为什么很多下载工具会失败

像 yt-dlp 这样的工具,主要是通过 HTTP 请求直接获取网页数据。

但 JS challenge 的逻辑是:

必须执行 JavaScript 才能获得访问凭证。

如果工具没有完整的浏览器环境,就会出现问题,例如:

没有 screen 对象 没有 canvas 没有 webgl 没有真实的 navigator 信息

即使某些工具尝试模拟这些环境,也很难做到完全一致。

因此服务器就会判定 challenge 失败。

于是工具就拿不到真正的页面数据,也就无法解析出所有的视频格式。

五、为什么 challenge 的代码经常看起来很乱

很多 JS challenge 只有几十 KB,但代码看起来非常复杂,变量名也很奇怪,比如:

_0x3a21 _0x7f9c

这是因为这些代码通常经过了混淆处理。

混淆的目的不是提高运行效率,而是增加分析难度。

通过:

随机变量名 字符串加密 控制流打乱 无意义计算

可以让代码非常难以阅读。

对普通浏览器来说,这些代码只需要执行即可; 但对试图逆向算法的程序来说,理解成本会非常高。

六、challenge 真正检测的是什么

如果把所有细节总结起来,JS challenge 实际上在检测的是:

JavaScript 是否能正常执行 浏览器环境是否完整 浏览器指纹是否合理 执行时间是否正常 行为模式是否像真人

换句话说,它并不是在挑战计算能力,而是在挑战:

来访者是不是真正的浏览器。

扩展阅读:


如何下载油管/Youtube上的在线视频?

如何下载 Youtube 上的视频到指定文件夹?

如何下载 Youtube 上特定码率的音视频?