文章总结: 这篇文章详细介绍了Vue路由守卫的权限控制机制及其绕过技巧。作者通过实际案例展示了如何通过修改登录响应中的roleType参数来绕过路由守卫,访问未授权页面,并分析了路由守卫的实现原理。文章还提出了另一种绕过思路:直接修改路由的requiresAuth值为false,并展示了自动化绕过脚本的实现和效果。这对于理解前端路由权限控制及其安全风险很有帮助。 综合评分: 85 文章分类: WEB安全,漏洞分析,渗透测试,实战经验,前端安全
Vue 路由守卫拦不住? | 实战案例带你拆解路由权限绕过技巧
原创
庆尘
Daylight庆尘
2025年9月19日 18:36
有一阵子没更新文章了,催更的师傅有点多哈哈,不知道发漏洞案例的分析文章还是发实战技巧的总结,也不知道师傅们喜欢看哪个(可以在留言里说哈,我看看下一篇文章写什么),不过前面几篇发的案例分析,今天就再讲讲理论技巧吧,希望师傅们看完之后都能有收获
,
今天我们的主题依然是围绕未授权访问漏洞,之前发过不少这方面的公开课、技巧总结以及案例分析的文章,相信师傅们对这个漏洞已经有了一定的认知。
01
引言
之前的文章和公开课里面也说过,我自己的网站测试流程,总共就抽象为三步(我也是我推荐我学员们测网站的流程),如下
01
现有功能点的测试
现有功能点简单来说就是你肉眼可见的功能点,这个可以测的范围就特别多,依据网站功能来测,例如SQL、XSS、SSRF、业务逻辑等等一系列漏洞
02
路由的测试
当现有功能测完之后,就可以开始分析路由了,这个简单来说,就是找到你肉眼不可见的功能或页面,我抽象理解为路由,可以尝试拼接访问,记住,找路由的目的只是为了更方便的测试接口,并不能证明有没有漏洞,而具体测试类型和方法过多,这里就不多赘述了
02
接口的测试
当现有功能点测完,路由也尝试去寻找了,这时候就需要进行网站测试的最后一步——测接口,你可以理解为尝试调用任何在这个网站你本不该有权限调用的接口,例如你是普通用户,JS中发现路径-/newoa/api/getAlluserlist,这个就是很明显的高权限接口。记住,接口鉴权才是未授权测试的终点
今天我们讲一讲第二步中的路由测试,在这一过程中,我们已经总结出了一套完整的路由寻找和测试的方法,这里简单讲一个针对VUE框架的路由测试方法
02
案例引入
先来看一个漏洞案例
首先,我以一个普通用户的身份登入某个系统,页面如下
首先对站点的现有功能进行测试,测完之后开始对路由进行测试
从Findsomething中发现一个地址如下
/ecustportrayal/front/examineRecords
根据站点其他页面的URL分析得知这个路径是路由而非接口,并获取到其对应的baseurl,拼接访问之后发现页面一片空白,如下
而且中间没有加载任何数据包,那这就很奇怪了,已知路由存在,且baseurl正确,那拼接之后不应该能正常访问吗,就算是内部的接口做鉴权,那也应该页面一闪而逝,或者干脆只回显出页面,而数据由于鉴权的问题回显不出来
但现在很明显,我们访问路由的操作都被阻止了,这到底是为什么呢。我经常能听到很多师傅说过类似的话——“页面做了鉴权”,“路由做了鉴权”等等,这个其实是正确的,确实是路由层面做了限制,用来限制不同角色用户所能访问的页面,在VUE框架中,做路由鉴权最常用的手法就是——路由守卫
在经过一系列查找和测试中,发现该站点用户登录时,会发送一个如下的数据包
于是我设置一个自动替换,将响应中的roleType参数值从4改为1
此时退出,然后重新登录,再次访问刚才我们找到的路由
成功回显页面,并接管审核后台,如下
当然,这里能有数据的原因是因为对应的接口其实也没做鉴权,但我们现在关注的问题是,为什么改了个响应就能够访问这个路由了?很显然,这里的路由鉴权是跟响应中的roleType相关的,这个路由鉴权在代码层到底是怎么实现的?我们针对这种场景又有什么测试方法呢?
03
路由守卫介绍
在 Web 应用中,前端路由控制着用户在应用中的导航路径。对于需要认证的页面,通常我们会使用路由守卫来进行权限控制,以防止未授权的用户访问。
来看一段最简单的路由守卫的demo实现代码。
假设应用中有几个页面,其中 "/dashboard" 和 "/userManage" 是需要认证才能访问的,而 "/login" 是公开的页面。
// 定义路由映射关系const routes = [ { path: '/login', //路径 name: 'Login', // 路由唯一标识 component: Login, // 路由对应的页面组件 meta: { // 路由鉴权标记 requiresAuth: false } }, { path: '/dashboard', name: 'Dashboard', component: Dashboard, meta: { requiresAuth: true } }, { path: '/userManage', name: 'UserManage', component: UserManage, meta: { requiresAuth: true } }]
const router = new VueRouter({ mode: 'history', routes})
// 全局前置守卫router.beforeEach((to, from, next) => { // 检查目标路由是否需要登录 if (to.meta.requiresAuth) { // 检查本地存储中的登录状态 const isLoggedIn = localStorage.getItem('isLoggedIn') === 'true'
if (isLoggedIn) { // 已登录,允许访问 next() } else { // 未登录,重定向到登录页,并记录当前路径以便登录后返回 next({ path: '/login', query: { redirect: to.fullPath } // 将当前要访问的路径作为参数传递给登录页 }) } } else { // 不需要登录的页面,直接放行 next() }})
简单解读一下这段代码
#
项目中有如下路由配置:
// 定义路由映射关系const routes = [ { path: ‘/login’, //路径 name: ‘Login’, // 路由唯一标识 component: Login, // 路由对应的页面组件 meta: { // 路由鉴权标记 requiresAuth: false } }, { path: ‘/dashboard’, name: ‘Dashboard’, component: Dashboard, meta: { requiresAuth: true } }, { path: ‘/userManage’, name: ‘UserManage’, component: UserManage, meta: { requiresAuth: true } }]
在这段代码中,"/dashiboard" 和 "/userManage" 路由上都设置了
meta: { requiresAuth: true }
表明这些页面需要认证。而 "/login" 路由则不需要任何认证,任何人都可以访问。
既然设计了需要认证,自然就要写对应的认证逻辑,为了保护需要认证的页面,项目中使用了 Vue Router 的 beforeEach 路由守卫来验证用户是否已经认证,如下
// 全局前置守卫router.beforeEach((to, from, next) => { // 检查目标路由是否需要登录 if (to.meta.requiresAuth) { // 检查本地存储中的登录状态 const isLoggedIn = localStorage.getItem(‘isLoggedIn’) === ‘true’ if (isLoggedIn) { // 已登录,允许访问 next() } else { // 未登录,重定向到登录页,并记录当前路径以便登录后返回 next({ path: ‘/login’, query: { redirect: to.fullPath } // 将当前要访问的路径作为参数传递给登录页 }) } } else { // 不需要登录的页面,直接放行 next() }})
例如,当用户访问/userManage时,该段代码会查找userManage路由的requiresAuth值,判断页面是否需要认证,若需要认证,则走判断逻辑,也就是此处的检查本地存储中的登录状态
这里只是demo代码,有的开发会去跟后端交互判断鉴权信息是否有效,不过前端存储依然非常多
当判断用户已经登录时,则执行next(),即允许用户进行跳转,反之则跳转登录页,这样就实现了页面,即路由层面的鉴权
04
案例原理分析
好,现在我们已经了解了路由守卫的设计流程,再回过来看我们刚才的那个漏洞,在登录时后端返回了一个roleType
根据我们的测试,得知这个roleType就是路由鉴权的依据,并且也挖到了漏洞,但为什么访问那个路由被拦截的时候没有任何的数据包呢,它是怎么识别到我登录时的roleType值的呢?
答案就是——缓存
现在我们的猜想是,当用户登录时发起这个请求包,后端返回roleType值,这个值被一直存储在缓存
路由映射与路由守卫的demo代码如下
const routes = [ { path: '/examineRecords', //路径 name: 'examineRecords', // 路由唯一标识 component: examineRecords, // 路由对应的页面组件 meta: { // 路由鉴权标记 requiresAuth: true } }]
// 全局前置守卫router.beforeEach((to, from, next) => { // 从localStorage中获取roleType的值 const roleType = localStorage.getItem('roleType'); if (to.meta.requiresAuth) { if (roleType=1) { // 认为用户是管理员 next() } else { // 认为不是管理员 next({ path: '/login', query: { redirect: to.fullPath } // 将当前要访问的路径作为参数传递给登录页 }) } } })
此时用户访问/ecustportrayal/front/examineRecords路由
若登录时返回的roleType是4,则在路由守卫逻辑中,会走到else,导致无法跳转。当我们修改响应,把roleType改为1时,缓存中给的roleType也就变为了。此时又由于路由守卫逻辑是从缓存中取出roleType值,这时取出来的值为1,自然就被前端认为是管理员,从而能够正常跳转
那么这,就是最开始被拦截以及修改响应为什么绕过拦截的原因,当然,此时我们只是猜想
好,此时访问后台的审核页面查看缓存,来印证我们的猜想
果然不出我们所料,在缓存中找到了存储的roleType值
这不一切都能对上了吗,我果然是有点天赋的。在我看来,分析出漏洞原理的过程真的是种享受哈哈
05
绕过思路简介
虽然 Vue Router 提供了强大的路由控制功能,但这些功能主要依赖于浏览器端的 JavaScript 代码,容易被绕过。通过对 Vue 应用和路由实例的分析,我们可以通过一些技巧绕过认证限制。
#
再来看一下示例demo代码
const routes = [ { path: '/examineRecords', //路径 name: 'examineRecords', // 路由唯一标识 component: examineRecords, // 路由对应的页面组件 meta: { // 路由鉴权标记 requiresAuth: true } }]
// 全局前置守卫router.beforeEach((to, from, next) => { // 从localStorage中获取roleType的值 const roleType = localStorage.getItem('roleType'); if (to.meta.requiresAuth) { if (roleType=1) { // 认为用户是管理员 next() } else { // 认为不是管理员 next({ path: '/login', query: { redirect: to.fullPath } // 将当前要访问的路径作为参数传递给登录页 }) } } else { // 不需要登录的页面,直接放行 next() }})
刚才这个漏洞,我们绕过的思路是通过误导
if (to.meta.requiresAuth) { ......}
内的判断逻辑,来让路由守卫认为我们有权限,那师傅们仔细看看这个代码,我们还有什么方式能够绕过路由守卫,正常触发跳转吗?
-思考中-
答案——修改要跳转的路由的requiresAuth值为false
看到这个答案是不是一下就豁然开朗了,为什么一定要去研究需要认证路由的认证逻辑呢?直接让这个路由变为不需要认证的,访问时连认证逻辑都不会走
// 全局前置守卫router.beforeEach((to, from, next) => { // 从localStorage中获取roleType的值 const roleType = localStorage.getItem('roleType'); if (to.meta.requiresAuth) { ...... } else { // 不需要登录的页面,直接放行 next() }})
当对应路由的requiresAuth为false时,前端认为这个路由是公开路由,不需要进行权限校验,就会直接走到else,然后触发next从而正常跳转
这个流程是可以通过脚本以及一系列方法实现自动化的,碰到VUE页面自动修改所有的路由鉴权标记(因为路由meta中的鉴权标记并不一定都是requiresAuth,只是规范化开发一般都用的这个而已),这样在VUE场景的路由测试中就会方便很多(当然,也并不是一定会生效,只是适配部分这种路由守卫场景而已)
简单介绍一下脚本开发和实现逻辑
01
查找Vue实例和Vue Router
遍历DOM树以及特定函数实现
02
识别meta鉴权标记并修改路由权限
遍历路由查找鉴权标记(此处不能仅查找requiresAuth,因为路由meta中的鉴权标记名并不一定都是requiresAuth,只是规范化开发一般都用的这个而已)
02
清除路由守卫
防止触发认证相关钩子
效果演示如下
正常打开靶场页面
点击个人中心,由于我给个人中心设置了路由守卫,所以提示跳转失败

配置好自动化绕过后,重新打开靶场页面

直接点击个人中心,成功跳转个人中心页面

配置自动化绕过之后,全程无需任何操作,师傅们也可以根据思路尝试自己设计一下绕过脚本,并思考如何才能实现JS脚本的纯自动化
07
结语
通过这篇文章,简单了解了 Vue 前端路由的权限控制机制,虽然前端路由权限控制非常方便,但并不意味着应用是完全安全的。当然,也有很多设计得很好很安全的路由守卫,这里只是简单分析了一种。
#
#
师傅们看完了是不是对之前遇到的有些场景豁然开朗了,看完了觉得有收获的师傅可以点个赞支持一下,一起期待下次更精彩的案例吧,最后,希望师傅们都能到越来越多的漏洞!
#
最后插个广告:本人亲带SRC课程,想咨询课程的师傅可以来联系我哈,支持随时插班(混口饭吃)
别让”入门慢”拖慢你的脚步|庆尘Src三期课程来袭——聚焦独家漏洞挖掘技巧
查看原文:《Vue 路由守卫拦不住? | 实战案例带你拆解路由权限绕过技巧》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论