nuxt3路由守卫攻击面研究

在 Nuxt 3 中,我们可以通过路由守卫来控制页面访问权限,比如检查用户是否登录、进行JWT权限验证,或者在路由跳转前执行特定操作,一贯使用 Angular 和 Nextjs 的我,这次来用了 Nuxt3,发现 Nuxt 3 提供了几种实现方式,包括使用中间件(Middleware)、Vue Router 钩子以及组件内生命周期函数

1.通过 Middleware 管理路由访问

在 Nuxt 3 中,推荐使用中间件来处理页面访问控制,中间件可以在页面渲染之前拦截路由请求,并执行自定义逻辑

比如我们先创建一个 auth.js

1
2
3
4
5
6
7
8
9
10
11
12
// middleware/auth.js
export default defineNuxtRouteMiddleware((to) => {
// 登录不需要校验
const openRoutes = ['/login', '/register']
// 如果在白名单内,直接通过
if (openRoutes.includes(to.path)) return
// 检查 token
const token = useCookie('token').value
if (!token) {
return navigateTo('/login')
}
})

然后再页面或者布局中应用中间件,比如在 SPA 下

1
2
3
4
5
6
7
<script setup>
const pageGuard = 'auth'
// 配置页面元信息
definePageMeta(() => ({
middleware: pageGuard
}))
</script>

布局应用中间件

1
2
3
4
5
<script setup>
defineLayoutMeta({
middleware: 'auth' // 所有使用该布局的页面都会生效
})
</script>

全局中间件,如果想要在全局页面生肖可以在 nuxt.config.ts 设置

1
2
3
4
5
export default defineNuxtConfig({
router: {
middleware: ['auth'] // 全局应用
}
})

2. 使用 Vue Router 的 beforeEach 钩子

Nuxt 3 默认使用 Vue Router,因此可以直接利用 Vue Router 的全局导航守卫进行控制

1
2
3
4
5
6
7
8
9
10
11
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
router.beforeEach((to, from) => {
const currentUser = useState('currentUser')
// 如果未登录并且不是去登录页,强制跳转
if (!currentUser.value && to.name !== 'login') {
return { name: 'login' }
}
})
</script>

这里每次路由切换时都会触发,可以处理登录验证、权限控制或其他自定义逻辑

3. 页面组建中的路由狗子

在 Vue 组件中,还可以用 onBeforeRouteLeaveonBeforeRouteUpdate 钩子处理路由变化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script setup>
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
// 离开当前页面前执行
onBeforeRouteLeave((to, from) => {
if (confirm('确定要离开当前页面吗?未保存的数据将丢失')) {
return true
} else {
return false
}
})
// 当同一路由参数更新时触发
onBeforeRouteUpdate((to, from) => {
console.log('路由参数已变更:', to.params)
})
</script>

TIPS:

  • onBeforeRouteLeave:用于阻止用户离开页面(如表单未保存提示)
  • onBeforeRouteUpdate:用于同一路由下参数变化时的逻辑处理

4. 授权检查示例

1
2
3
4
5
6
export default defineNuxtRouteMiddleware((to) => {
const currentUser = useState('currentUser')
if (!currentUser.value && to.name !== 'login') {
return navigateTo('/login')
}
})

带来的攻击面?

前端路由守卫配置错误

比如有些人认为配置了

1
middleware: 'auth'

就能保护一些关键页面、像后台,或者一些增删改查的页面,但是我们可以通过修改 localStorage 或者 cookie 来跳过 Router 从而跳过认证直接访问页面

这个比较简单,比如我们可以伪造一个 Cookie 或者修改自身的 localStorage 实则得看业务点是怎样的

1
localStorage.setItem('user', JSON.stringify({ admin: true }))

重定向逻辑错误

这个比较常见,一些开发者会配置一些像下面这样的代码

1
return navigateTo(to.query.redirect)

那这还说啥了,瞎几把跳转呗

1
https://iloli.gov/login?redirect=https://iloli.moe

DoS

这个在理论阶段,实战中我还没遇到过,如果遇到了那顶多是那种SSR处理的服务器会出问题,客户端基本上 DoS 没啥软用,一般漏洞点会出现在 beforeEach 上,通过逻辑配置错误导致的 DoS

1
2
3
router.beforeEach((to, from) => {
if (!user) return navigateTo('/login')
})

就是会一直

1
/login -> /login -> /login

过度信任query/params

这个带来的危害就是XSS了,也可以搭配CSRF来用,具体得看场景,不过现在前端基本上都自带xss了,这玩意可以忽略了,除非有脑残手动开启 dangerouslySetInnerHTML 或者直接用 v-html

References