Vue路由守卫拦不住?|实战案例带你拆解路由权限绕过技巧

admin 2025-12-22 03:56:45 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 这篇文章详细介绍了Vue路由守卫的权限控制机制及其绕过技巧。作者通过实际案例展示了如何通过修改登录响应中的roleType参数来绕过路由守卫,访问未授权页面,并分析了路由守卫的实现原理。文章还提出了另一种绕过思路:直接修改路由的requiresAuth值为false,并展示了自动化绕过脚本的实现和效果。这对于理解前端路由权限控制及其安全风险很有帮助。 综合评分: 85 文章分类: WEB安全,漏洞分析,渗透测试,实战经验,前端安全


cover_image

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

清除路由守卫

防止触发认证相关钩子

效果演示如下

正常打开靶场页面

点击个人中心,由于我给个人中心设置了路由守卫,所以提示跳转失败

![](https://mmbiz.qpic.cn/mmbiz_png/mK8kXuuyDk9zcv9j8gpv8O8iciazib9oo8cXmjuOHst4YbFQQwReu6XVFf1HibSJ5qDCT2ZMgupUThPqyz4r4M5YgA/640?wx_fmt=png&from=appmsg)

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

![](https://mmbiz.qpic.cn/mmbiz_png/mK8kXuuyDk9zcv9j8gpv8O8iciazib9oo8cDKQibGnmNpfLfMZfOAEA616trSVxbNPjpxpXA9fDaBfhUgfBZB4Ta6w/640?wx_fmt=png&from=appmsg)

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

![](https://mmbiz.qpic.cn/mmbiz_png/mK8kXuuyDk9zcv9j8gpv8O8iciazib9oo8cTKMXgXSEP5gqQiauX77XI4835PQVQJDbALUEqQVRdCSu7cMtRAsMLPQ/640?wx_fmt=png&from=appmsg)

配置自动化绕过之后,全程无需任何操作,师傅们也可以根据思路尝试自己设计一下绕过脚本,并思考如何才能实现JS脚本的纯自动化

07

结语

通过这篇文章,简单了解了 Vue 前端路由的权限控制机制,虽然前端路由权限控制非常方便,但并不意味着应用是完全安全的。当然,也有很多设计得很好很安全的路由守卫,这里只是简单分析了一种。

#

#

师傅们看完了是不是对之前遇到的有些场景豁然开朗了,看完了觉得有收获的师傅可以点个赞支持一下,一起期待下次更精彩的案例吧,最后,希望师傅们都能到越来越多的漏洞!

#

最后插个广告:本人亲带SRC课程,想咨询课程的师傅可以来联系我哈,支持随时插班(混口饭吃)

别让”入门慢”拖慢你的脚步|庆尘Src三期课程来袭——聚焦独家漏洞挖掘技巧


查看原文:《Vue 路由守卫拦不住? | 实战案例带你拆解路由权限绕过技巧》

评论:0   参与:  8