Vue安全实践:敏感状态保护与错误处理指南之一
Vue 安全实践:敏感状态保护与错误边界处理
敏感状态的客户端保护
在 Vue 应用中,敏感状态(如用户凭证、权限信息等)的保护至关重要。以下是几种关键保护策略:
1. 避免直接存储敏感数据
// 不推荐
data() {
return {
userToken: localStorage.getItem('token'), // 敏感数据直接存储
creditCardNumber: null
}
}
// 推荐做法
export default {
data() {
return {
auth: null // 仅存储认证状态
}
},
methods: {
async login(credentials) {
const response = await authService.login(credentials)
this.auth = { isAuthenticated: true }
// 不存储token,使用httpOnly cookie
}
}
}
实践建议:
- 使用 HTTP-only cookies 存储会话令牌
- 敏感数据应尽量保存在服务端,前端只保留必要的最小状态
- 考虑使用 Web Crypto API 对必须存储在客户端的敏感数据进行加密
2. 响应式数据的保护
import { shallowRef, markRaw } from 'vue'
export default {
setup() {
const sensitiveData = shallowRef(markRaw({
secretKey: 'should-not-be-reactive'
}))
return { sensitiveData }
}
}
为什么有效:
shallowRef
只对 value 的引用变化做出响应markRaw
标记对象永远不会被转为响应式代理
3. 权限控制模式
实现示例:
// 权限指令
app.directive('permission', {
mounted(el, binding) {
const { hasPermission } = useAuth()
if (!hasPermission(binding.value)) {
el.parentNode?.removeChild(el)
}
}
})
// 使用方式
<button v-permission="'admin'">删除用户</button>
异步操作的错误边界处理
1. 全局错误处理
// main.js
app.config.errorHandler = (err, vm, info) => {
console.error('全局错误:', err)
sentry.captureException(err)
// 显示友好错误界面
}
2. 错误边界组件
// ErrorBoundary.vue
<script setup>
import { ref, onErrorCaptured } from 'vue'
const error = ref(null)
onErrorCaptured((err, instance, info) => {
error.value = err
return false // 阻止错误继续向上传播
})
</script>
<template>
<slot v-if="!error" />
<div v-else class="error-fallback">
<h3>抱歉,出了点问题</h3>
<button @click="error = null">重试</button>
</div>
</template>
// 使用方式
<ErrorBoundary>
<AsyncComponent />
</ErrorBoundary>
3. 异步操作的最佳实践
// 组合式函数封装
export function useSafeAsync(asyncFn) {
const loading = ref(false)
const error = ref(null)
const data = ref(null)
const execute = async (...args) => {
try {
loading.value = true
error.value = null
data.value = await asyncFn(...args)
} catch (err) {
error.value = err
throw err // 可选择是否继续抛出
} finally {
loading.value = false
}
}
return { loading, error, data, execute }
}
// 使用示例
const { loading, error, data, execute } = useSafeAsync(fetchUserData)
execute(userId)
实践建议:
- 为所有异步操作添加超时控制
- 实现重试机制(指数退避算法)
- 区分可恢复错误和不可恢复错误
- 记录错误日志但不要暴露敏感信息
4. 错误状态管理
// 错误状态模块 (Vuex/Pinia)
export const useErrorStore = defineStore('error', {
state: () => ({
errors: [],
unhandledError: null
}),
actions: {
capture(error, context = {}) {
this.errors.push({ error, timestamp: Date.now(), ...context })
if (!context.handled) {
this.unhandledError = error
}
},
clearUnhandled() {
this.unhandledError = null
}
}
})
// 在组件中使用
const errorStore = useErrorStore()
try {
await riskyOperation()
} catch (err) {
errorStore.capture(err, {
handled: true,
component: 'UserProfile'
})
}
安全与错误处理的综合策略
- 深度防御:在客户端、网络层和服务端都实施保护
- 最小权限:前端也应遵循最小权限原则
- 优雅降级:当错误发生时提供有意义的备选方案
- 监控报警:集成错误监控系统(如 Sentry)
- 安全审计:定期检查前端代码中的敏感数据处理
通过以上实践,可以显著提高 Vue 应用的安全性和健壮性,同时提供更好的用户体验。
评论已关闭