反反爬虫实战:手撕某知名网站Webpack加密的JavaScript

在反反爬虫领域,Webpack 打包加密是主流网站常用的防护手段 ------ 它通过模块混淆、变量压缩、动态加载等方式,让爬虫工程师难以定位核心请求逻辑。本文将以实战视角,从原理拆解到步骤落地,带你一步步 "撕开" 某知名网站的 Webpack 加密 JS,还原其数据请求的关键逻辑。

一、先搞懂:Webpack 加密的核心原理

Webpack 本身是前端模块打包工具,并非 "加密工具",但网站会基于 Webpack 的特性做二次防护,形成反爬虫壁垒。其核心手段主要有三类:

  1. 模块碎片化打包 网站会将 JS 代码拆分为多个 chunk(代码块),核心加密逻辑(如签名、Token 生成)单独打包成独立模块,通过require或动态import加载,而非平铺在一个文件中,增加定位难度。

  2. 变量与函数名混淆 借助 Terser 等工具,将关键变量(如secretKeytimestamp)重命名为无意义的abc,函数名改为_0x123_0x456,同时删除注释、压缩空格,让代码可读性大幅降低。

  3. 动态注入与执行 部分加密逻辑会通过evalnew Function等方式动态生成代码并执行,甚至会结合页面 DOM 元素(如某个隐藏标签的内容)作为加密参数,进一步增加静态分析的难度。

二、实战准备:工具与环境

工欲善其事,先备好以下工具,覆盖 "抓包 - 调试 - 反混淆" 全流程:

  • Chrome 开发者工具(DevTools):核心工具,用于抓包、断点调试、查看调用栈。
  • Node.js:用于本地运行拆解后的 JS 代码,验证加密逻辑正确性。
  • 反混淆工具 :推荐js-beautify(代码格式化)、deobfuscator.io(在线反混淆)、AST Explorer(基于抽象语法树的深度反混淆)。
  • 抓包工具(可选):如 Fiddler 或 Charles,用于拦截并保存目标网站的 JS 文件,避免浏览器刷新丢失资源。

三、分步拆解:手撕 Webpack 加密 JS

以 "定位某网站的 Token 生成逻辑" 为例,分 5 步落地实战:

步骤 1:定位 Webpack 加密入口 ------ 找到核心 JS 文件

首先要确定 Webpack 打包后的 "主入口" 和 "加密模块",关键是抓包 + 筛选:

  1. 打开 Chrome DevTools,切换到Network面板,筛选 "JS" 类型请求,刷新目标页面。
  2. 找到命名含 hash 的 "主 JS 文件"(通常 Size 最大,且加载顺序靠前,如main.8a7b6c.js),这是 Webpack 的入口文件。
  3. 观察是否有 "动态加载的 chunk":若页面触发数据请求时(如点击分页、下拉刷新),新加载了chunk-123.4d5e6f.js,大概率包含加密逻辑,优先标记该文件。

步骤 2:反混淆初处理 ------ 让代码 "可读"

Webpack 打包后的 JS 通常是压缩混淆状态,第一步先格式化代码:

  1. 在 DevTools 的Sources 面板中,找到步骤 1 标记的 JS 文件,右键选择 "Pretty print"(格式化代码,图标为{}),此时代码会按缩进排列,便于查看。
  2. 若变量名仍为ab等无意义字符,复制代码到deobfuscator.io,选择 "反混淆" 模式,工具会自动还原部分变量名、拆解evalnew Function动态代码。
  3. 对于复杂混淆(如控制流平坦化),需用AST Explorer:将代码粘贴到左侧,选择 "JavaScript" 和 "@babel/parser",右侧编写 AST 处理脚本(如批量重命名变量),深度清理混淆。

步骤 3:梳理模块依赖 ------ 找到加密函数所在模块

Webpack 会通过 "模块 ID" 管理依赖,核心是找到 "加密函数" 的调用关系:

  1. 格式化后的代码中,找到 Webpack 的 "模块定义" 部分,通常是一个匿名函数,内部包含modules对象(键为模块 ID,值为模块函数),例如:

    javascript

    运行

    复制代码
    (function(modules) {
      // 模块加载逻辑
      function __webpack_require__(moduleId) { ... }
      return __webpack_require__(0); // 入口模块ID通常为0
    })({
      0: function(module, exports, __webpack_require__) {
        // 入口模块代码,会调用其他模块
        var encrypt = __webpack_require__(123); // 假设123是加密模块ID
      },
      123: function(module, exports) {
        // 加密模块代码,包含Token生成逻辑
        exports.generateToken = function(timestamp) { ... }
      }
    })
  2. 定位关键关键词:在 Sources 面板按Ctrl+F搜索与加密相关的关键词,如tokensignencrypttimestamp,找到包含这些关键词的模块(如上例中的模块 123)。

  3. 跟踪调用栈:在关键词所在行设置 "断点",刷新页面或触发数据请求,当代码执行到断点时,查看Call Stack(调用栈),逆向找到 "谁调用了这个加密函数",确认其参数来源(如是否从页面 Cookie、DOM 中获取)。

步骤 4:还原加密逻辑 ------ 拆解函数参数与算法

找到加密模块后,需逐行分析函数逻辑,还原其计算过程:

  1. 以模块 123 的generateToken函数为例,假设其代码如下(已初步反混淆):

    javascript

    运行

    复制代码
    exports.generateToken = function(t) {
      var e = "abc123xyz" + t; // t为时间戳
      var r = md5(e).toUpperCase(); // 对拼接后的字符串做MD5加密,转大写
      return r;
    }
  2. 关键是确认 "固定密钥" 和 "算法类型":上例中abc123xyz是固定密钥,算法为 MD5;若遇到复杂算法(如 HMAC-SHA256、RSA),可通过函数内的crypto相关方法(如CryptoJS.HmacSHA256)或自定义计算逻辑判断。

  3. 记录参数传递路径:确认t(时间戳)的生成方式(如Date.now()/new Date().getTime())、是否有其他参数(如用户 ID、页面 URL)参与加密。

步骤 5:本地验证 ------ 用 Node.js 复现加密结果

为确保逻辑还原正确,需在本地编写代码验证:

  1. 安装依赖:若加密算法为 MD5,执行npm install crypto-js

  2. 编写验证脚本: javascript

    运行

    复制代码
    const CryptoJS = require('crypto-js');
    
    // 还原的加密函数
    function generateToken(timestamp) {
      const secretKey = "abc123xyz";
      const str = secretKey + timestamp;
      const token = CryptoJS.MD5(str).toString().toUpperCase();
      return token;
    }
    
    // 测试:用当前时间戳生成Token
    const t = Date.now();
    const token = generateToken(t);
    console.log("时间戳:", t);
    console.log("生成的Token:", token);
  3. 对比结果:运行脚本,将生成的 Token 与浏览器中 "Network" 面板里请求的token参数对比,若一致,则说明加密逻辑已完全还原。

四、关键注意事项:避坑与合规

  1. 法律合规是前提所有反反爬虫操作必须基于 "获得网站官方授权",严禁对未授权网站进行爬取,避免触犯《网络安全法》《反不正当竞争法》。
  2. 应对动态更新网站会定期更新 Webpack 打包规则(如变更模块 ID、修改加密算法),需定期重新抓包分析,可通过 "监控 JS 文件 hash 变化" 及时发现更新。
  3. 慎用自动化工具 避免直接使用市面上的 "一键反混淆" 工具处理敏感代码,部分工具可能植入恶意脚本;建议本地部署开源反混淆工具(如js-deobfuscator)。

五、总结与进阶方向

本次实战的核心逻辑是 "定位入口→反混淆→追调用栈→还原算法→本地验证",关键在于耐心分析 Webpack 的模块结构,以及善用 DevTools 的断点调试功能。

若想进一步提升,可深入学习AST(抽象语法树) 技术 ------ 通过编写 AST 转换脚本,自动批量还原混淆变量名、拆解控制流平坦化,大幅提升反混淆效率;同时可研究 "Webpack Runtime" 机制,理解其模块加载原理,更精准地定位动态加载的加密模块。

相关推荐
专注前端30年4 小时前
Vue CLI与Webpack:区别解析与实战使用指南
前端·vue.js·webpack
余道各努力,千里自同风4 小时前
如何使用 Promise.all() 处理异步并发操作?
开发语言·前端·javascript
营赢盈英4 小时前
How to detect if <html> tag has a class in child Angular component
前端·javascript·css·html·angular.js
Achieve - 前端实验室4 小时前
深入浅出 ES Module
前端·javascript
拖拉斯旋风4 小时前
深入理解 JavaScript 字符串声明与现代迭代实践
javascript
AAA阿giao4 小时前
从零开始构建一个基于 AIGC 的图像生成应用:用 Node.js 把想象变成画面
javascript·aigc
残冬醉离殇5 小时前
🔥 什么?不用鼠标点击也能触发点击事件???前端工程师的认知塌了!
前端·javascript
前端小咸鱼一条5 小时前
14. setState是异步更新
开发语言·前端·javascript
gustt5 小时前
JavaScript 字符串深度解析:模板字符串与常用方法详解
前端·javascript·代码规范