Webpack 与源码泄露
一个没删的 .map 文件,等于把前端源码、接口清单和业务逻辑一起交出去。
一个被忽略的构建产物
前端打包之后,浏览器跑的是压缩混淆过的 main.xxxx.js。为了线上报错能定位到源码行号,Webpack 会生成一个 .map 文件,里面是「压缩后的位置 ↔ 原始文件」的完整映射,通常还带着 sourcesContent——原始源码全文。
生产环境不该留它。留了,就是源码泄露。
怎么判断有没有
三种方式,从快到慢:
- 浏览器插件。Wappalyzer 看框架,SourceDetectorMap 这类插件会自动探测当前站点有没有
.map。 - 看 JS 末尾。打开任意一个 bundle,最后一行常有
//# sourceMappingURL=main.xxxx.js.map。 - 直接猜。
/static/js/main.xxxx.js.map,把.js后面加.map试一下。200 就是有。
第三种最土,但命中率不低——很多人只在打包配置里关掉了「生成」,没清理历史文件。
还原源码
npm install -g reverse-sourcemap
reverse-sourcemap --output-dir ./src main.xxxx.js.map
还原出来的是完整的目录结构:src/views/、src/api/、src/router/、src/utils/。Vue 项目还原后基本可以直接读,<template> 都在。
这一步之后,你手上就是一份完整的前端源码。不用猜接口,不用翻 JS,直接读。
读什么
按价值排序:
src/api/ 或 src/services/。所有接口路径、参数名、请求方法都在这里。有了这份清单,后面的接口测试不需要再爬。
src/router/。路由表告诉你系统有哪些页面,包括那些没在菜单里显示的(hidden: true)。隐藏路由经常是管理功能。
src/utils/。加密、签名、脱敏的实现。前端加密基本等于没有加密——密钥在源码里。
src/config/。环境配置、第三方 key、内网地址。
.env 相关。如果构建时被内联进去,VUE_APP_* 这类变量都能读到。
一个真实的链路
某 OA 系统的登录口,常规手法全部无效。翻到 .js.map,还原出源码,发现几十个接口。
其中几个接口不需要鉴权,返回的是组织架构、用户列表——信息泄露,但不足以突破登录。
于是换思路:拿这套系统的指纹去找同款。找到一个测试环境,用超管账号登录,抓包看到一个接口:
/api/user/getInfoByToken?token=eyJ...
这个接口只校验 token 有效性,不校验 token 归属。把测试环境的 token 拿到生产环境试——返回了生产环境管理员的账号和密码哈希。
密码是裸 MD5,撞库几分钟就出来了。
从「一个没删的 map 文件」到「管理员权限」,中间没有任何漏洞利用技巧,全是信息串联。
同类问题:接口清单本身
就算没有 .map,前端 JS 里也散落着接口路径。
# 从 JS 里批量提取路径
cat *.js | grep -oE '"/[a-zA-Z0-9_/-]{3,}"' | sort -u
提取出来的路径直接批量请求,看哪些返回 200、哪些不需要登录。这个动作在授权测试里属于常规操作,但要注意请求频率——几千个路径无脑打,等于对目标做了一次压测。
修复
- 生产构建关闭 sourcemap:
devtool: false、build.productionSourceMap: false。 - 已经生成的
.map从发布目录删掉,不是不引用,是删除。 - 前端不要放密钥。任何在浏览器里能读到的东西,都不算秘密。
- 接口鉴权在后端做,不要依赖前端路由守卫。
参考
- 《Webpack 漏洞利用:从 .map 文件到敏感接口》,公众号 渗透安全HackTwo