一、渗透测试的困境:当登录页成为拦路虎
在一次针对某金融科技公司的安全测试中,我遇到了典型的单页应用(SPA)场景:打开首页是简洁的登录界面,输入框下方闪烁着"请登录后访问"的提示。尝试常见的弱口令爆破无果后,看着浏览器控制台里频繁报错的401 Unauthorized
,突然意识到——这又是一个被前端鉴权层层包裹的SPA应用。这类应用就像一个精致的玻璃盒,表面光滑无瑕,却把核心功能紧锁其中。
(一)SPA的双面性:丰富接口与鉴权陷阱
现代Web应用中,SPA凭借用户体验优势占据半壁江山。打开任意一个主流管理后台、数据中台,大概率会遇到Vue、React或Next.js构建的单页应用。这类应用的特点是:接口密度极高,一个中等规模的后台可能包含数百个API,但前端路由系统往往通过"鉴权标记"将未登录用户挡在门外。安全测试人员面对的常是这样的场景:浏览器里只有一个登录页,抓包工具显示的请求寥寥无几,仿佛整个应用在未登录时处于"休眠状态"。
(二)传统爬虫的无力感
记得三年前测试某电商后台时,使用传统爬虫遍历链接,整整跑了8小时只抓到登录接口和静态资源。直到手动分析前端代码,才发现所有功能页面的路由都被auth: true
标记保护,而这些信息根本不会出现在未登录状态的HTML中。这让我意识到:对付SPA,必须跳出"爬取可见链接"的传统思维,从框架层入手挖掘隐藏的路由地图。
二、框架识别:打开路由地图的钥匙
(一)为什么要精准识别框架?
在某政务云平台测试中,我曾误将Vue应用当作React处理,导致后续的路由解析失败。痛定思痛后总结出框架识别的核心价值:
-
路径枚举效率:不同框架的路由存储方式差异显著,Vue的 $router
、Next.js的文件系统路由、Angular的RouterModule
,每种框架都有其独特的"路径字典" -
鉴权绕过策略:SPA的鉴权标记通常与框架深度耦合,Vue的 meta.auth
、React的react-router-dom
守卫,识别框架才能精准定位并修改鉴权属性 -
兼容性处理:比如Vue3的 __vue_app__
与Vue2的$router
在挂载点上的差异,正确识别版本才能避免脚本错误
(二)主流框架识别实战
1. Vue框架:从全局变量到DOM渗透
在某能源管理系统的测试中,通过以下步骤确认其使用Vue.js:
-
第一步:全局变量探测
打开控制台输入typeof window.__VUE__ !== 'undefined' || typeof window.Vue !== 'undefined'
,返回true
,初步锁定Vue框架。但遇到过某些谨慎的开发者会移除全局变量,这时需要进入DOM层探测。 -
第二步:DOM元素扫描
执行const vueElements = document.querySelectorAll('*');
后遍历元素,在一个<div id="app">
标签上发现el.__vue__
属性,确认无误。这里有个小技巧:优先扫描带有id="app"
或data-vue-root
属性的元素,它们通常是Vue的根节点。
拿到根节点后,获取$router
对象是关键。在Vue2项目中,window.$router
通常直接可用;但在Vue3的组合式API项目中,可能需要通过divObject.__vue_app__.config.globalProperties.$router
获取。曾在一个医疗后台项目中遇到特殊情况:开发者将$router
挂载在自定义的window.appRouter
变量上,最终通过递归查找解决(见下方代码),但需注意递归深度控制,避免浏览器卡顿。
functionrecursiveFindRouterWithPush(obj, depth = 0, maxDepth = 5) {
if (depth > maxDepth) returnnull;
for (const key in obj) {
try {
if (key === '$router' && obj[key]?.beforeEach instanceofFunction) {
return obj[key];
}
} catch (error) { /* 忽略不可枚举属性 */ }
if (typeof obj[key] === 'object' && obj[key] !== null) {
const subResult = recursiveFindRouterWithPush(obj[key], depth + 1, maxDepth);
if (subResult) return subResult;
}
}
returnnull;
}
2. Next.js:从数据标签到文件路由
在测试某跨境电商后台时,通过三种方式确认Next.js框架:
-
全局数据探测: window.__NEXT_DATA__
对象的存在是最直接的标志,这个包含页面初始化数据的对象,是Next.js服务端渲染的典型特征 -
标签扫描: <meta name="next-head">
标签和/_next/
路径的脚本文件,如同Next.js的"胎记",在多个项目中屡试不爽 -
路由特性验证:尝试访问 /api/auth/check
,返回404而非空白页面,符合Next.js文件系统路由的特性(API路由需在pages/api
目录下)
识别Next.js后,其路由枚举方式与Vue截然不同——无需通过$router
,直接解析__NEXT_DATA__.props.pageProps.router.routes
即可获取所有注册路径,这得益于Next.js基于文件系统的路由设计。
3. React:从根节点到纤维树
在某AI客服平台的测试中,通过以下步骤识别React:
-
全局变量检测: window.React
或__REACT_DEVTOOLS_GLOBAL_HOOK__
的存在,表明项目使用React框架 -
根节点分析:找到 id="root"
的根节点,遍历其属性,发现以__reactFiber$
开头的属性,这是React纤维树的内部标记 -
组件结构验证:查看页面源代码,发现大量 data-reactroot
属性的标签,结合控制台中React.Component
的构造函数,双重确认框架类型
对于使用react-router-dom
的项目,路由信息通常存储在window.history
对象或组件状态中,需要通过逆向工程的方式解析,这比Vue和Next.js稍显复杂。
4. Angular:从全局对象到版本标记
在某制造业管理系统的测试中,通过两步确认Angular:
-
全局对象检测: window.angular
或window.ng
的存在,是Angular最直接的标志 -
DOM属性扫描:查找带有 ng-version
属性的标签,该属性会显示Angular的具体版本号,如ng-version="14.2.3"
Angular的路由系统@angular/router
通常需要通过注入的Router
对象获取,但在动态爬虫中,直接检测框架存在即可为后续鉴权绕过提供策略依据。
三、鉴权突破:前端标记的逆向操作
(一)SPA鉴权的本质:前端门卫与后端保镖
在某证券交易平台的测试中,发现其鉴权机制分为两层:
-
前端拦截:通过路由守卫(如Vue的 beforeEach
)检查meta.auth
属性,未登录时跳转登录页 -
后端验证:即使绕过前端拦截,API请求仍需携带 Authorization
头,否则返回403
这揭示了SPA鉴权的真相:前端拦截是"温柔的门卫",而后端验证才是"硬核保镖"。但安全测试的第一步,就是先放倒这个"门卫",让爬虫能进入内部空间,才有机会发现可能存在的后端漏洞。
(二)Vue框架鉴权移除实战
在某教育平台后台的测试中,成功通过以下步骤绕过前端鉴权:
-
获取完整路由列表
使用foundRouter.getRoutes()
而非options.routes
,前者会包含动态加载的子路由,在该项目中多获取到17个隐藏路径。
const routes = foundRouter.getRoutes();
console.log('Detected', routes.length, 'routes'); // 输出42条路由
-
批量修改鉴权标记
遍历路由的meta
属性,将所有包含"auth"关键词的属性设为false
。需要注意的是,部分项目会使用自定义属性如requiresAuth
、authRequired
,因此匹配时采用模糊检测key.includes('auth')
。
routes.forEach(route => {
for (const key in route.meta) {
if (route.meta.hasOwnProperty(key) && key.toLowerCase().includes('auth')) {
console.log(`Modifying auth flag for ${route.path}: ${route.meta[key]} -> false`);
route.meta[key] = false;
}
}
});
-
导航到受限页面
使用foundRouter.push('/admin/dashboard')
而非浏览器地址栏输入,避免JavaScript上下文重置。在该项目中,访问/admin/user/export
时,虽然后端仍返回403,但成功触发了/api/user/export
的API请求,通过分析请求参数,最终发现未授权访问漏洞。
(三)例外情况处理
在某银行后台项目中,遇到了反制措施:
-
动态鉴权属性:部分路由的 meta.auth
属性通过API动态加载,页面初始化时不存在,需模拟用户交互触发加载 -
路由守卫加密:某React项目使用混淆后的路由守卫, meta
属性被加密为Base64字符串,需先解密再修改 -
性能陷阱:递归查找 $router
时曾导致浏览器内存占用飙升,通过设置maxDepth=5
和超时机制解决
四、实战经验:从漏洞发现到面试加分
(一)漏洞发现的"运气加成"
在某物流管理系统中,修改鉴权后访问/audit/log/delete
,虽然后端返回403,但通过分析请求体,发现该接口接受all=true
参数,尝试不带认证头直接POST请求,意外发现接口未校验管理员权限,导致任意日志删除漏洞。这说明:即使前端鉴权被绕过,后端验证可能存在疏漏,而动态爬虫的价值就在于创造"触发接口"的机会。
(二)面试中的加分技巧
当面试官问及"无账号情况下如何测试登录保护"时,可按以下思路回答:
-
框架识别三板斧:先通过全局变量、DOM属性、特征标签确定技术栈 -
路由枚举策略:根据框架特性获取完整路径列表,如Vue的 getRoutes()
、Next.js的__NEXT_DATA__
-
鉴权绕过实操:修改路由元数据,模拟用户导航,触发隐藏接口 -
后续测试重点:强调前端绕过只是起点,需结合Burp Suite分析后端响应,重点关注 401/403
响应中的细节
(三)工具化思考
在团队协作中,曾将框架识别和鉴权绕过功能封装成Chrome扩展,实现:
-
一键框架检测:点击按钮自动识别技术栈并生成报告 -
智能路由枚举:根据框架类型选择最优路径获取方式 -
鉴权批量移除:支持正则匹配鉴权属性,避免误操作
五、风险提示:技术边界与合规性
(一)法律红线不可触碰
需要明确的是,上述技巧仅适用于授权安全测试场景。在某案例中,未经允许使用框架识别工具探测某政府网站,被WAF识别为恶意攻击,触发警方调查。因此,任何测试必须获得明确授权,且数据仅限测试环境使用。
(二)后端验证的必然性
必须牢记:前端鉴权绕过不代表漏洞存在,仅是测试的起点。在90%的项目中,绕过前端后仍会遇到后端认证,如JWT校验、会话令牌检查等。但正是这10%的例外,可能隐藏着高风险漏洞,如未授权访问、水平越权等。
(三)性能与稳定性平衡
在大规模扫描中,递归查找$router
、批量修改路由属性可能导致浏览器崩溃。建议:
-
对Vue项目优先使用 window.$router
,避免深度递归 -
控制路由遍历速度,添加 setTimeout
防止浏览器假死 -
对每个修改的路由进行快照备份,测试结束后恢复原状
六、总结:在细节中寻找突破
从最初面对登录页的束手无策,到如今熟练运用框架识别技巧,我深刻体会到:安全测试的突破点往往藏在技术栈的细节中。SPA的路由系统、鉴权标记、框架特性,这些看似普通的技术选型,却构成了渗透测试的关键路径。
下次当你面对一个"只有登录页"的应用时,不妨按照这个流程试试:打开控制台,先做框架识别,再拿路由列表,接着修改鉴权标记,最后模拟导航触发接口。也许在某个隐藏的/admin/debug
页面里,正藏着你苦苦寻找的漏洞。记住,技术的魅力就在于——当大多数人被表面的登录页挡住时,少数人能通过框架层的洞察,打开新的测试维度。
本文涉及的技术仅用于授权安全测试,未经允许的网络探测可能触犯法律。安全测试需在合规框架下进行,共建网络安全生态。
原文始发于微信公众号(网络侦查研究院):动态爬虫实战:从框架识别到鉴权突破的渗透技巧
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论