当前位置: 首页 > web >正文

Vue 项目安全设置方案:XSS/CSRF 防护指南

在 Vue 项目中实施全面的 XSS 和 CSRF 防护需要前后端协同配合。以下是完整的实现方案:

Vue 前端安全配置方案

1. XSS 防御策略

安全数据渲染方案
<template><div><!-- 安全文本渲染(自动转义) --><p>{{ userInput }}</p><!-- HTML 内容渲染(使用 DOMPurify 净化) --><div v-if="trustedContent" v-html="sanitizedHtml"></div></div>
</template><script>
import DOMPurify from 'dompurify';export default {data() {return {userInput: '<script>alert("XSS")<\/script>',trustedContent: '<b>安全内容</b>'};},computed: {sanitizedHtml() {// 使用 DOMPurify 净化 HTMLreturn DOMPurify.sanitize(this.trustedContent, {ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'], // 仅允许安全标签ALLOWED_ATTR: ['href', 'title'] // 仅允许安全属性});}}
};
</script>
URL 参数安全处理
// 在请求 URL 参数时进行编码
const unsafeValue = "<script>malicious</script>";
const safeParam = encodeURIComponent(unsafeValue);this.$http.get(`/api/data?param=${safeParam}`);
内容安全策略 (CSP) 设置
// 在 public/index.html 的 head 中添加 CSP meta 标签
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'nonce-random123' https://trusted.cdn.com;style-src 'self' 'unsafe-inline';img-src 'self' data:; connect-src 'self';font-src 'self';object-src 'none';frame-src 'none';
">

2. CSRF 防护策略

Axios 全局配置
// src/utils/http.js
import axios from 'axios';
import store from '@/store';const http = axios.create({baseURL: process.env.VUE_APP_API_BASE_URL,timeout: 10000,
});// 请求拦截器:自动添加 CSRF Token
http.interceptors.request.use(config => {if (['post', 'put', 'patch', 'delete'].includes(config.method.toLowerCase())) {config.headers['X-CSRF-Token'] = store.state.csrfToken;}return config;
});// 响应拦截器:处理 403 错误(CSRF 失效)
http.interceptors.response.use(response => response,error => {if (error.response?.status === 403) {store.dispatch('refreshCSRF'); // 刷新 CSRF Token// 可选:自动重新发送原始请求return http.request(error.config);}return Promise.reject(error);}
);export default http;
CSRF Token 存储与刷新
// Vuex store 模块
const securityModule = {namespaced: true,state: {csrfToken: null},mutations: {SET_CSRF_TOKEN(state, token) {// 基本验证if (typeof token === 'string' && token.length >= 32) {state.csrfToken = token;}}},actions: {async fetchCSRFToken({ commit }) {try {const response = await http.get('/api/csrf-token');commit('SET_CSRF_TOKEN', response.data.token);// 设置 token 到 meta 标签(可选,SSR 场景下)let meta = document.querySelector('meta[name="csrf-token"]');if (!meta) {meta = document.createElement('meta');meta.name = 'csrf-token';document.head.appendChild(meta);}meta.content = response.data.token;} catch (error) {console.error('获取 CSRF Token 失败', error);}}}
};

3. 路由安全防护

// src/router/index.js
const router = new VueRouter({routes: [// ...{path: '/admin',component: AdminPanel,meta: { requiresAuth: true,capabilities: ['admin']}}]
});router.beforeEach((to, from, next) => {// 检查认证需求if (to.matched.some(record => record.meta.requiresAuth)) {if (!store.getters.isAuthenticated) {next({path: '/login',query: { redirect: to.fullPath }});return;}// 检查权限const requiredCapabilities = to.meta.capabilities || [];if (requiredCapabilities.length > 0 && !store.getters.hasCapabilities(requiredCapabilities)) {next('/forbidden'); // 无权限页面return;}}// 每次路由切换滚动到顶部window.scrollTo(0, 0);next();
});

4. Vuex 安全实践

// 增强安全性的 Vuex store
export default new Vuex.Store({state: {userData: null},mutations: {// 数据存储前的净化处理SET_USER_DATA(state, rawData) {// 执行深层次的净化state.userData = deepSanitize(rawData);}},actions: {// 安全获取用户数据async fetchUserData({ commit }, userId) {try {const response = await http.get(`/api/users/${userId}`);commit('SET_USER_DATA', response.data);} catch (error) {handleSecurityError(error);}}}
});// 深层数据净化函数
function deepSanitize(data) {if (typeof data === 'string') {// 移除 HTML 标签return data.replace(/<[^>]*>/g, '');} if (Array.isArray(data)) {return data.map(item => deepSanitize(item));}if (typeof data === 'object' && data !== null) {return Object.keys(data).reduce((acc, key) => {acc[key] = deepSanitize(data[key]);return acc;}, {});}return data;
}// 安全错误处理
function handleSecurityError(error) {if (error.response) {switch (error.response.status) {case 401:// 处理未认证错误router.push('/login');break;case 403:// 处理未授权错误store.dispatch('handleForbidden');break;case 419:// CSRF Token 失效store.dispatch('refreshCSRF');break;default:console.error('API Error:', error);}}
}

服务端配合实现(Node.js 示例)

1. CSRF Token 生成与验证

// 使用 Express + csurf 中间件
const express = require('express');
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const helmet = require('helmet');const app = express();
app.use(cookieParser());
app.use(express.json());// 设置 CSRF 保护
const csrfProtection = csrf({cookie: {httpOnly: true,secure: process.env.NODE_ENV === 'production',sameSite: 'strict',maxAge: 86400 // 1 天}
});// 提供 CSRF Token 端点
app.get('/api/csrf-token', csrfProtection, (req, res) => {res.json({ token: req.csrfToken() });
});// 受保护的 API 端点
app.post('/api/update-profile', csrfProtection, (req, res) => {try {// 1. 验证输入(使用验证库)// 2. 处理业务逻辑// 3. 返回响应res.json({ success: true });} catch (error) {handleSecurityError(res, error);}
});// 错误处理中间件
function handleSecurityError(res, error) {if (error.name === 'ValidationError') {res.status(400).json({ error: '无效请求' });} else {res.status(500).json({ error: '服务器错误' });}
}

2. HTTP 安全头设置

// 使用 Helmet 设置安全头
app.use(helmet({contentSecurityPolicy: {directives: {defaultSrc: ["'self'"],scriptSrc: ["'self'", "'nonce-random123'", "trusted-cdn.example.com"],styleSrc: ["'self'", "'unsafe-inline'"],imgSrc: ["'self'", "data:"],connectSrc: ["'self'"],fontSrc: ["'self'"],objectSrc: ["'none'"],frameSrc: ["'none'"]}},xssFilter: true,noSniff: true,frameguard: { action: 'deny' },hsts: {maxAge: 31536000, // 1 年includeSubDomains: true},referrerPolicy: { policy: 'same-origin' }
}));

3. 输入验证与净化

// 使用验证库,例如 Joi
const Joi = require('joi');const userSchema = Joi.object({username: Joi.string().alphanum().min(3).max(30).required(),email: Joi.string().email({minDomainSegments: 2,tlds: { allow: ['com', 'net', 'org'] }}).required(),bio: Joi.string().max(500).optional().escapeHTML() // 清除 HTML
});app.post('/api/users', csrfProtection, (req, res) => {const { error, value } = userSchema.validate(req.body);if (error) {return res.status(400).json({ error: error.details[0].message });}// value 现在是安全、净化后的数据createUser(value);
});

项目部署安全配置

Nginx 示例配置

server {listen 443 ssl;server_name yourdomain.com;ssl_certificate /path/to/cert.pem;ssl_certificate_key /path/to/privkey.pem;# Security headersadd_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-random123' trusted-cdn.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-src 'none';";add_header X-Content-Type-Options "nosniff";add_header X-Frame-Options "DENY";add_header X-XSS-Protection "1; mode=block";add_header Referrer-Policy "same-origin";add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;# Vue applocation / {root /usr/share/nginx/html;index index.html;try_files $uri $uri/ /index.html;}# API proxylocation /api/ {proxy_pass http://backend-service:3000/api/;proxy_http_version 1.1;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection 'upgrade';}
}

最佳实践检查清单

XSS 防护

  • 所有动态 HTML 渲染使用 DOMPurify.sanitize()
  • 严格限制 v-html 指令的使用
  • 内容安全策略 (CSP) 正确配置并启用
  • URL 参数值使用 encodeURIComponent 处理
  • 禁用内联事件处理(如:onclick="..."
  • 设置 Cookie 的 HttpOnlySecure 标志

CSRF 防护

  • 所有状态变更请求(POST/PUT/PATCH/DELETE)均包含 CSRF Token
  • Token 生成、传输和存储安全
  • Token 随每个请求变化(一次性使用最佳)
  • Cookie 设置 SameSite=StrictLax
  • API 端点验证 Origin/Referer

框架级防护

  • Vue 生产环境模式启用
  • 定期使用 npm audit 检查依赖漏洞
  • Vue Router 路由守卫实现权限控制
  • 禁用 Vue 配置中的 Devtools 在生产环境(Vue.config.devtools = false

服务器协同

  • 所有响应设置安全头(X-Content-Type-Options, X-Frame-Options 等)
  • API 端点实施严格的输入验证
  • 敏感操作(如密码更改)增加二次认证
  • 使用 HTTPS 加密所有通信
  • API 启用 CORS 并严格配置白名单
  • 设置速率限制防止暴力破解

项目流程图

首页
子页面
未授权
已授权
GET 请求
状态变更请求
Token 无效
Token 有效
持续失败
用户访问
Vue 应用加载
获取 CSRF Token
检查路由权限
存储于 Vuex
跳转登录页
渲染页面
用户操作
直接发送
添加 CSRF Token
服务器验证
自动刷新 Token
并重试请求
执行操作
终止请求
提示用户

实际项目中应根据具体业务需求和安全等级要求进行调整。

http://www.xdnf.cn/news/17398.html

相关文章:

  • 【Linux】Linux增删改查命令大全(附频率评级)
  • 嵌入式 Linux 驱动开发常见问题排查宝典(驱动开发篇)v1.0
  • imx6ull-驱动开发篇14——原子操作
  • WPF 动画卡顿
  • 机器学习支持向量机(SVM)
  • C++基础学习笔记
  • 谈谈SQL计算存储引擎中的索引和计算
  • 数据结构5-哈希表
  • AI搜索引擎——DeepSeek崛起 || #AIcoding·八月创作之星挑战赛# || 简单版
  • SwiftUI中的键盘快捷键、初始页面控制及网络权限管理解析
  • 安装部署K8S集群环境(实测有效版本)
  • SpringCloud基础
  • sqlite的sql语法与技术架构研究
  • 专题二_滑动窗口_将x减到0的最小操作数
  • 强遮挡场景误检率↓79%!陌讯多模态融合算法在充电桩占位检测的实战优化
  • 等保测评-Nginx中间件
  • 计算机毕业设计java疫情防控形势下的高校食堂订餐管理系统 高校食堂订餐管理系统在疫情防控背景下的设计与实现 疫情防控期间高校食堂线上订餐管理平台
  • 【感知机】感知机(perceptron)学习算法的对偶形式
  • 专题二_滑动窗口_长度最小的子数组
  • OpenAI推出开源GPT-oss-120b与GPT-oss-20b突破性大模型,支持商用与灵活部署!
  • AI代码审查大文档处理技术实践
  • Express框架
  • 机器学习之随机森林(Random Forest)实战案例
  • 一种基于CEEMDAN-小波阈值联合降噪-快速谱峭度(FSK)/基尼谱Ginigram/Autogram的故障诊断 Matlab
  • 动手学深度学习(pytorch版):第一章节——引言
  • Linux---第三天---权限
  • Ethereum: 像Uniswap V3贡献者一样开发,克隆、编译与测试v3-core
  • 二叉树算法之【中序遍历】
  • 最新教程 | CentOS 7 内网环境 Nginx + ECharts 页面离线部署手册(RPM 安装方式)
  • Kotlin中String的==相等比较符