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

需要掌握的前端安全概念以及实操

前言

在前端开发领域,安全问题如同隐藏在代码深处的暗礁,稍有不慎就可能让产品陷入漏洞风险。尤其是在面试场景中,面试官往往会跳出概念考核,直击「如何在实际开发中落地安全防护」的核心能力。作为高频考点的 XSS、CSRF、CSP、Clickjacking 等安全问题,不仅需要理解原理,更要掌握与主流框架(如 Vue、React、Next.js)深度结合的实践方案。

下文就将的技术栈:Vue、React、Next.js,谈一谈总结到的解决方法。

XSS(跨站脚本攻击)

  • Vue:

    默认转义:使用 {{ }} 插值时自动转义 HTML。

​ 风险点:v-html 指令会渲染原始 HTML,需用 DOMPurify 等库净化内容。

<div v-html="purifiedContent"></div>
<script>
import DOMPurify from 'dompurify';
export default {data() { return { content: '<script>alert(1)</script>' }; },computed: {purifiedContent() { return DOMPurify.sanitize(this.content); }}
};
</script>
  • React:

​ 自动转义:JSX 中的变量会被转义。
​ 风险点:dangerouslySetInnerHTML,需净化内容。

import DOMPurify from 'dompurify';
function SafeComponent({ content }) {const clean = DOMPurify.sanitize(content);return <div dangerouslySetInnerHTML={{ __html: clean }} />;
}

CSRF(跨站请求伪造)

  • 通用方案:

​ 后端生成 CSRF Token,前端在请求头或表单中携带。
​ 设置 Cookie 的 SameSite 属性为 Strict 或 Lax,同网站,同域名等。

  • Next.js 示例(API 路由):

    // 生成 Token 并存入 Session
    import { csrfToken } from 'csrf';
    export async function getServerSideProps(context) {const token = csrfToken(context.req);return { props: { token } };
    }
    // 提交时验证
    export default function handler(req, res) {if (req.method === 'POST') {if (!validateCsrfToken(req.headers['x-csrf-token'], req.session.token)) {return res.status(403).json({ error: 'Invalid CSRF token' });}}
    }

CSP(内容安全策略)

内容安全策略(CSP)是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本(XSS)和数据注入攻击等。无论是数据盗取、网站内容污染还是恶意软件分发,这些攻击都是主要的手段。

CSP 被设计成完全向后兼容(除 CSP2 在向后兼容有明确提及的不一致; 更多细节查看这里 章节 1.1)。不支持 CSP 的浏览器也能与实现了 CSP 的服务器正常工作,反之亦然:不支持 CSP 的浏览器只会忽略它,如常运行,默认为网页内容使用标准的同源策略。如果网站不提供 CSP 标头,浏览器也使用标准的同源策略。

对加载内容、图片、媒体资源和脚本策略控制。具体示例可参考MDN

  • Next.js 配置(next.config.js):

​ 示例使用的是严格安全策略。

module.exports = {async headers() {return [{source: '/(.*)',headers: [{key: 'Content-Security-Policy',value: "default-src 'self'; script-src 'self' 'unsafe-inline'"}]}];}
};

点击劫持(Clickjacking)

X-Frame-Options HTTP 响应头是用来给浏览器指示允许一个页面可否在 ](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Reference/Elements/frame)、[](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Reference/Elements/embed) 或者 [ 中展现的标记。站点可以通过确保网站没有被嵌入到别人的站点里面,从而避免点击劫持攻击。

仅当访问文档的用户使用支持 X-Frame-Options 的浏览器时,此附加的安全性才会被提供。

具体案例介绍查看MDN

  • Next.js 设置 HTTP 头:
// next.config.js
headers: [{key: 'X-Frame-Options',value: 'DENY'
}]

依赖安全

  • 使用 npm audit 或 yarn audit 检查漏洞,集成 Snyk 或 Dependabot 自动更新。

​ 说明:Dependabot是Github提供的功能,需要在github仓库中设置并打开。

​ 一份相关的配置文件.github/dependabot.yml参考如下:

version: 2
updates:- package-ecosystem: "npm" # 表示依赖项是 npm 包directory: "/" # 表示依赖文件位于仓库的根目录schedule:interval: "daily" # 每天检查更新versioning-strategy: increase # 更新到更高的版本allow:# 可以指定允许更新的包名- dependency-name: "express"ignore:# 可以指定忽略的包名和版本范围- dependency-name: "moment"versions: [">=2.0.0"]

CORS(跨域资源共享)

跨源资源共享(CORS,或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其他源(域、协议或端口),使得浏览器允许这些源访问加载自己的资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的“预检”请求。在预检中,浏览器发送的头中标示有 HTTP 方法和真实请求中会用到的头。

跨源 HTTP 请求的一个例子:运行在 https://domain-a.com 的 JavaScript 代码使用 XMLHttpRequest 来发起一个到 https://domain-b.com/data.json 的请求。

其它相关概念参考MDN。

  • Next.js
// next.config.js
module.exports = {async headers() {return [{source: '/api/(.*)',headers: [{ key: 'Access-Control-Allow-Origin', value: 'https://trusted-domain.com' },{ key: 'Access-Control-Allow-Methods', value: 'GET,POST' },],}];},
};

框架/技术栈特有安全实践

Vue
  • 服务端渲染(SSR):避免直接将用户输入注入模板,使用 vue-server-renderer 的 createRenderer 自动转义。
  • 第三方库:谨慎使用 vue-sanitize 等插件过滤内容
React
  • 属性注入风险:检查动态属性(如 href)是否包含 javascript:
const userInput = 'javascript:alert(1)';
<a href={userInput}>Click</a> // 危险!
// 解决方案:校验协议
const safeUrl = userInput.startsWith('http') ? userInput : '#';
  • PropTypes 校验:防止传递危险内容。
import PropTypes from 'prop-types';
MyComponent.propTypes = { content: PropTypes.string.isRequired };
Next.js
  • API 路由安全:

​ 身份验证:使用 next-auth 库管理会话。
​ 输入验证:使用 zod 或 yup 校验请求体。

  • 中间件防护(Next.js 12+):
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(req) {const token = req.cookies.get('auth-token');if (!token) return NextResponse.redirect('/login');return NextResponse.next();
}
  • 静态资源 SRI:在 next.config.js 中为脚本添加完整性校验。

  • Next.js一些安全头的配置

// next.config.js
module.exports = {async headers() {return [{source: '/(.*)',headers: [// 防御 XSS{ key: 'X-XSS-Protection', value: '1; mode=block' },// 禁止 MIME 类型嗅探{ key: 'X-Content-Type-Options', value: 'nosniff' },// 防止点击劫持{ key: 'X-Frame-Options', value: 'DENY' },// 严格 CSP(需根据项目调整){ key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self' 'unsafe-inline'" },],},];},
};

Vue 3 新增安全特性

  • 响应式数据边界
    Vue 3 的响应式系统通过 Proxy 实现,避免了 Vue 2 中 Object.defineProperty 的枚举漏洞(如恶意对象污染响应式数据)。
  • SFC 编译时转义
    在单文件组件(SFC)中,模板表达式会在编译阶段自动转义 HTML 字符,减少运行时 XSS 风险。
  • 自定义指令安全
    避免在自定义指令中直接操作 el.innerHTML,如需渲染动态内容,建议通过计算属性配合 DOMPurify:
<template><div v-my-directive="safeContent"></div>
</template>
<script>
import DOMPurify from 'dompurify';
export default {directives: {myDirective(el, { value }) {el.textContent = DOMPurify.sanitize(value); // 避免 innerHTML}},computed: {safeContent() {return DOMPurify.sanitize(this.userInput);}}
};
</script>

React 18+ 安全增强

  • 自动批处理边界
    React 18 的自动批处理机制可防止恶意代码通过 setTimeout 绕过批量更新,降低内存泄漏攻击风险。
  • 严格模式检测
    在 React.StrictMode 下会检测以下安全隐患:
<React.StrictMode>{/* 检测过时生命周期 */}{/* 检测未释放的 DOM 引用 */}{/* 检测意外的副作用重复执行 */}
</React.StrictMode>
  • 事件处理机制强化
    React 合成事件系统会自动转义事件处理函数中的用户输入(如 onClick 中的动态内容),进一步防范 XSS。

内存泄漏攻击(如 Prototype Pollution)

  • 场景
    恶意用户通过深度嵌套对象污染 JavaScript 原型链,导致全局逻辑被篡改(如 Array.prototype.push 被覆盖)。

  • 防御

在 Vue/React 中避免直接合并用户输入对象,使用 Object.assign({}, safeObj, userInput) 而非直接修改原型。

使用 immer 库处理不可变数据,其内部通过 produce 函数隔离原型污染风险:

// React 示例
import produce from 'immer';
const handleInput = useCallback((input) => {setState(produce((draft) => {draft.data = input; // immer 会创建新对象,避免原型污染}));
}, []);

浏览器指纹跟踪防御

  • 风险

攻击者通过浏览器指纹(如 navigator.hardwareConcurrency、canvas 指纹)唯一标识用户,绕过传统身份验证。

  • 防御
    在 Next.js 中配置 HTTP 头禁止浏览器指纹收集:
// next.config.js
module.exports = {async headers() {return [{source: '/',headers: [// 禁止浏览器暴露硬件信息{ key: 'Permissions-Policy', value: "hardware-concurrency=()", },// 随机化 canvas 指纹{ key: 'Cross-Origin-Embedder-Policy', value: 'require-corp', },{ key: 'Cross-Origin-Opener-Policy', value: 'same-origin', },],},];},
};
  • 使用第三方库主动混淆指纹特征。

更多的实际例子

前端无感刷新token(axios)
// Axios 拦截器示例(React)
axios.interceptors.response.use(response => response,async error => {const originalRequest = error.config;if (error.response.status === 401 && !originalRequest._retry) {originalRequest._retry = true;const newToken = await refreshToken(); // 调用刷新 Token 接口axios.defaults.headers.common['Authorization'] = `Bearer ${newToken}`;return axios(originalRequest);}return Promise.reject(error);}
);
动态加载脚本并添加完整性校验(SRI)
// Vue 示例
mounted() {const script = document.createElement('script');script.src = 'https://example.com/analytics.js';script.integrity = 'sha256-xxxx';script.crossOrigin = 'anonymous';document.head.appendChild(script);
}
使用rel=”noopener noreferrer”(防止钓鱼攻击)
// React 示例
<a href=" " target="_blank" rel="noopener noreferrer">Link</a >
对Next.js API请求采取请求速率限制
// 使用 `rate-limiter-flexible` 库
import { RateLimiterMemory } from 'rate-limiter-flexible';
const limiter = new RateLimiterMemory({ points: 5, duration: 60 });export default async function handler(req, res) {try {await limiter.consume(req.socket.remoteAddress);} catch {return res.status(429).json({ error: 'Too many requests' });}
}
文件上传限制上传类型和大小
  • 前端部分

    // React 示例
    <inputtype="file"accept=".jpg,.png"onChange={(e) => {if (e.target.files[0].size > 5 * 1024 * 1024) {alert('File too large!');}}}
    />
  • 后端二次验证

// pages/api/upload.js
import { createReadStream } from 'fs';
import fileType from 'file-type';export default async function handler(req, res) {const stream = createReadStream(req.file.path);const type = await fileType.fromStream(stream);if (!['jpg', 'png'].includes(type.ext)) {fs.unlinkSync(req.file.path); // 删除非法文件return res.status(400).json({ error: 'Invalid file type' });}
}
验证重定向参数
// Vue 路由守卫示例
router.beforeEach((to, from, next) => {if (to.query.redirect) {const allowedDomains = ['https://trusted.com', '/internal-path'];if (!allowedDomains.some(domain => to.query.redirect.startsWith(domain))) {delete to.query.redirect; // 删除非法重定向}}next();
});
客户端的敏感数据
  • 使用环境变量

    // .env.local
    API_KEY=xxxx// 页面中使用
    export async function getServerSideProps() {const data = await fetch('https://api.example.com', {headers: { Authorization: process.env.API_KEY },});
    }
  • 混淆前端代码(webpack terser)

    // next.config.js
    module.exports = {productionBrowserSourceMaps: false, // 禁用 Source Mapwebpack: (config) => {config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true;return config;},
    };
异常行为的监控

例如,登录失败五次以上,上传行为日志(获取到IP)

// pages/api/log.js
export default function handler(req, res) {if (req.body.action === 'login' && req.body.failedAttempts > 5) {console.warn(`Suspicious login activity from IP: ${req.socket.remoteAddress}`);// 发送告警到监控系统(如 Sentry)}res.status(200).end();
}
Cloudflare Turnstile 人机识别,防止自动化攻击

不收集用户隐私,只通过用户的行为模式。

  • 在前端网页中添加一个TurnStile的脚本,并渲染组件。
  • TurnStile在后台分析用户的行为模式(鼠标移动、点击频率)判断是否人为。
  • 生成token。如果验证通过,TurnStile会生成一个加密的Token,发送到后端验证。
  • 后端可通过Cloudflare的API,也可以通过云函数的方式验证Token的有效性,确保请求来自合法用户。

面试回答注意事项

Vue 中如何避免 XSS?
  • 答:避免使用 v-html,必须使用时用 DOMPurify 净化内容;确保服务端渲染时数据转义。
React 的 dangerouslySetInnerHTML 有什么风险?
  • 答:直接插入原始 HTML 可能导致 XSS,应始终先净化内容,并使用 DOMPurify 处理。
Next.js 中如何配置 CSP?
  • 答:在 next.config.js 的 headers 中设置 Content-Security-Policy,或使用自定义服务器中间件添加 HTTP 头。
如何防范 CSRF?Next.js 中的实现?
  • 答:使用 CSRF Token 验证,Next.js 可在 API 路由中通过 getServerSideProps 传递 Token,并在提交时校验。
JWT 存储在前端哪里最安全?
  • 答:存储在 httpOnly Cookie 中,避免被 XSS 窃取,同时设置 SameSite=Lax 和 Secure 标志(HTTPS)。

总结

  • 框架特性:Vue/React 的自动转义机制需配合安全实践(如避免危险 API),Next.js 需合理配置 HTTP 头和中间件。
  • 工具链:使用净化库(DOMPurify)、安全头扫描工具(SecurityHeaders.com)、依赖审计工具。
  • 开发习惯:永远不信任用户输入,输出前转义/净化,最小化第三方依赖风险。

相关文章:

  • 第8讲:坐标轴与刻度优化指南(字体、角度、格式处理)
  • 【C到Java的深度跃迁:从指针到对象,从过程到生态】第四模块·Java特性专精 —— 第十六章 多线程:从pthread到JMM的升维
  • OpenResty技术深度解析:原理、应用与生态对比-优雅草卓伊凡
  • 深入理解同源策略与跨域资源共享(CORS)
  • word插入APA格式的参考文献
  • Deepseek 生成新玩法:从文本到可下载 Word 文档?思路与实践
  • JVM 自动内存管理
  • 弹性盒子布局
  • 预训练大模型与元训练大模型在医疗AI项目中的选型对比分析
  • DELL R740服务器闪黄灯不开机故障案例
  • CSdiy java 05
  • 除了Object.freeze(),JavaScript中还有哪些优化性能的对象限制方法?
  • 蓝牙BLE
  • 蓝桥杯 18. 机器人繁殖
  • whois为什么有时会返回两个不同的域名状态
  • 【权限模型】RBAC模型详解
  • Spring Security源码解析
  • DeepSeek+Dify之三工作流引用知识库案例
  • 解锁服务器迁移的未来:《2025 服务器迁移效率白皮书》(附下载)
  • 安卓开发学习随记
  • 华侨城A:一季度营收53.63亿元,净利润亏损14.19亿元
  • 上海灵活就业人员公积金新政有哪些“创新点”?
  • 美媒:受关税政策影响,美国电商平台近千种商品平均涨价29%
  • 从 “沪惠保” 到 “沪骑保”看普惠保险的 “上海样式”
  • 伊朗爆炸港口已恢复货物进出口工作
  • 关键词看中国经济“一季报”:稳,开局良好看信心