news 2026/7/28 14:04:04

前端安全的七宗罪:XSS、CSRF、点击劫持到供应链攻击的防御清单

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端安全的七宗罪:XSS、CSRF、点击劫持到供应链攻击的防御清单

前端安全的七宗罪:XSS、CSRF、点击劫持到供应链攻击的防御清单

一、XSS 注入:前端安全的万恶之源

跨站脚本攻击(XSS)在 2026 年 OWASP Top 10 中仍然位列第三,原因是前端框架的普及让开发者产生了"框架自动防御 XSS"的错觉。React 和 Vue 确实默认转义了 JSX/模板中的变量,但当开发者使用dangerouslySetInnerHTMLv-html或直接在 DOM API 中插入未净化的内容时,XSS 漏洞仍然存在。

三类 XSS 的防御策略:

  • 存储型 XSS:服务端存储恶意脚本,其他用户访问时触发。防御:输入验证 + 输出编码。
  • 反射型 XSS:恶意脚本嵌入 URL 参数,即时反射执行。防御:对所有 URL 参数进行编码处理。
  • DOM 型 XSS:客户端 JavaScript 直接操作 DOM 时注入。防御:避免使用innerHTML,使用textContent替代。
// xss-defense.ts — XSS 防御工具集 import DOMPurify from 'dompurify'; // ===== 安全 HTML 渲染 ===== interface SanitizeConfig { /** 允许的 HTML 标签白名单 */ allowedTags?: string[]; /** 允许的属性白名单 */ allowedAttributes?: Record<string, string[]>; /** 最大输入长度(防止 DoS) */ maxLength?: number; } const DEFAULT_SANITIZE_CONFIG: Required<SanitizeConfig> = { allowedTags: ['b', 'i', 'em', 'strong', 'a', 'p', 'br', 'ul', 'ol', 'li'], allowedAttributes: { a: ['href', 'target', 'rel'], }, maxLength: 50000, }; /** * 净化用户输入的 HTML 内容,防止 XSS 攻击 */ function sanitizeHtml( dirty: string, config: SanitizeConfig = {}, ): { clean: string; wasSanitized: boolean } { const cfg = { ...DEFAULT_SANITIZE_CONFIG, ...config }; // 输入长度检查:防止 DoS 攻击 if (dirty.length > cfg.maxLength) { throw new Error(`输入内容过长(${dirty.length} 字符),已拒绝处理`); } const clean = DOMPurify.sanitize(dirty, { ALLOWED_TAGS: cfg.allowedTags, ALLOWED_ATTR: cfg.allowedAttributes ? Object.keys(cfg.allowedAttributes) : undefined, }); return { clean, wasSanitized: clean !== dirty, }; } // ===== URL 安全校验 ===== /** * 校验并净化 URL,防止 javascript: 和 data: 协议注入 */ function sanitizeUrl(url: string): string | null { // 去除前后空白 const trimmed = url.trim(); if (!trimmed) return null; try { const parsed = new URL(trimmed); // 只允许 http/https 协议 if (!['http:', 'https:'].includes(parsed.protocol)) { console.warn(`拒绝非安全协议的 URL: ${parsed.protocol}`); return null; } return parsed.href; } catch { // 相对路径:验证不包含危险协议 if (/^(javascript|data|vbscript):/i.test(trimmed)) { console.warn('拒绝危险协议的 URL'); return null; } return trimmed; } } // ===== React 安全渲染组件 ===== function SafeHtml({ html, className }: { html: string; className?: string }) { const [sanitizedHtml, setSanitizedHtml] = useState(''); useEffect(() => { try { const { clean } = sanitizeHtml(html); setSanitizedHtml(clean); } catch (err) { console.error('HTML 净化失败:', err instanceof Error ? err.message : String(err)); setSanitizedHtml(''); } }, [html]); if (!sanitizedHtml) { return null; } return ( <div className={className} dangerouslySetInnerHTML={{ __html: sanitizedHtml }} /> ); } export { sanitizeHtml, sanitizeUrl, SafeHtml };

二、CSRF 防御体系的演化

CSRF(跨站请求伪造)在 SPA 时代并未消失,只是攻击面从传统表单提交转移到了 API 调用。2026 年主流的防御策略已从 Synchronizer Token Pattern 演进为 SameSite Cookie + 自定义请求头的双重防御。

// csrf-defense.ts — 前端 CSRF 防御实践 interface CsrfConfig { /** Token 获取端点 */ tokenEndpoint: string; /** 自定义请求头名称 */ headerName: string; /** Token 过期时间(毫秒) */ tokenTtl: number; } const DEFAULT_CSRF_CONFIG: CsrfConfig = { tokenEndpoint: '/api/csrf-token', headerName: 'X-CSRF-Token', tokenTtl: 60 * 60 * 1000, // 1 小时 }; class CsrfProtection { private token: string | null = null; private tokenExpiry: number = 0; private config: CsrfConfig; constructor(config: Partial<CsrfConfig> = {}) { this.config = { ...DEFAULT_CSRF_CONFIG, ...config }; } /** 获取或刷新 CSRF Token */ async getToken(): Promise<string> { const now = Date.now(); // 如果 token 仍然有效,直接返回 if (this.token && now < this.tokenExpiry) { return this.token; } try { const response = await fetch(this.config.tokenEndpoint, { method: 'GET', credentials: 'same-origin', }); if (!response.ok) { throw new Error(`获取 CSRF Token 失败: HTTP ${response.status}`); } const data = (await response.json()) as { token: string }; this.token = data.token; this.tokenExpiry = now + this.config.tokenTtl; return data.token; } catch (err) { console.error('CSRF Token 获取异常:', err instanceof Error ? err.message : String(err)); throw err; } } /** 为请求附加 CSRF 保护 */ async attachToRequest(init: RequestInit = {}): Promise<RequestInit> { const token = await this.getToken(); return { ...init, headers: { ...init.headers, [this.config.headerName]: token, // 额外的 CSRF 防御层:自定义请求头 'X-Requested-With': 'XMLHttpRequest', }, credentials: 'same-origin', }; } } // 全局 fetch 包装器 const csrf = new CsrfProtection(); async function secureFetch( url: string, init: RequestInit = {}, ): Promise<Response> { // 对于修改状态的方法,附加 CSRF Token const methods = ['POST', 'PUT', 'PATCH', 'DELETE']; const requiresCsrf = methods.includes(init.method?.toUpperCase() ?? 'GET'); if (requiresCsrf) { init = await csrf.attachToRequest(init); } return fetch(url, init); } export { CsrfProtection, secureFetch };

三、点击劫持:消失的威胁还是隐藏的漏洞?

点击劫持(Clickjacking)通过透明 iframe 诱使用户点击看似无害的页面元素,实际触发了被覆盖页面的操作。防御手段是设置 HTTP 响应头X-Frame-Options: DENYContent-Security-Policy: frame-ancestors 'none',但前端也可以通过frame-busting脚本作为兜底。

// frame-busting.ts — 点击劫持防御(客户端兜底) /** * 检测当前页面是否被嵌入 iframe 中(点击劫持风险) * 注:服务端应优先使用 X-Frame-Options / CSP frame-ancestors */ function detectClickjacking(): { embedded: boolean; topOrigin: string | null } { try { // 跨域情况下访问 top.location 会抛出异常 if (window.top && window.top !== window.self) { const topOrigin = window.top.location.origin; return { embedded: true, topOrigin: topOrigin !== window.location.origin ? topOrigin : null, }; } } catch { // 跨域访问被阻止,说明被非可信域名嵌入 return { embedded: true, topOrigin: 'unknown (cross-origin)', }; } return { embedded: false, topOrigin: null }; } /** * 防御性 frame-busting:将被劫持的页面跳出 iframe * 仅在检测到异常嵌入时执行 */ function frameBusting() { const { embedded, topOrigin } = detectClickjacking(); if (!embedded) return; if (window.self !== window.top) { try { // 记录安全事件 console.warn('检测到点击劫持风险,来源:', topOrigin); // 尝试跳出 iframe(同源情况下有效) if (window.top) { window.top.location.href = window.location.href; } } catch { // 跨域情况下 browser 已阻止访问,安全 } } } // 页面加载后执行 if (typeof window !== 'undefined') { frameBusting(); }

四、供应链攻击:从 npm 到 CDN 的信任链断点

前端供应链攻击的节点包括:NPM 依赖投毒、CDN 资源劫持、构建工具插件漏洞、环境变量泄露。防御层次:

// supply-chain-defense.ts — 前端供应链防御检查 interface SRIHash { url: string; integrity: string; // sha384-... 哈希值 crossorigin?: 'anonymous' | 'use-credentials'; } // ===== 子资源完整性(SRI)校验配置 ===== // 对 CDN 资源启用 SRI 校验,防止 CDN 被劫持后注入恶意代码 const SRI_CONFIG: SRIHash[] = [ { url: 'https://cdn.example.com/react/18.2.0/react.production.min.js', integrity: 'sha384-...{实际哈希}', // 构建时自动生成 crossorigin: 'anonymous', }, ]; /** * 验证加载的 script 标签是否包含 SRI 校验 */ function validateSRIScripts(): string[] { const issues: string[] = []; const scripts = document.querySelectorAll('script[src]'); scripts.forEach((script) => { const src = script.getAttribute('src') ?? ''; // 跳过同源脚本 if (!src.startsWith('http')) return; const integrity = script.getAttribute('integrity'); const crossOrigin = script.getAttribute('crossorigin'); if (!integrity) { issues.push(`CDN 脚本缺少 SRI 校验: ${src}`); } if (!crossOrigin && script.hasAttribute('integrity')) { issues.push(`带 integrity 的脚本缺少 crossorigin 属性: ${src}`); } }); return issues; } // ===== 环境变量泄露检测 ===== /** * 检测前端代码中是否泄露了敏感环境变量 */ function detectLeakedEnvVars(envPrefix: string[] = ['SECRET_', 'PRIVATE_', 'API_KEY_']): string[] { const leaked: string[] = []; for (const key of Object.keys(import.meta.env ?? {})) { for (const prefix of envPrefix) { if (key.startsWith(prefix)) { leaked.push(`敏感环境变量 "${key}" 可能在客户端代码中暴露`); } } } return leaked; } // 页面加载完成后运行安全检查 document.addEventListener('DOMContentLoaded', () => { const sriIssues = validateSRIScripts(); if (sriIssues.length > 0) { console.warn('SRI 校验问题:', sriIssues); } const envLeaks = detectLeakedEnvVars(); if (envLeaks.length > 0) { console.warn('环境变量泄露风险:', envLeaks); } });

五、总结

前端安全的七类威胁——XSS、CSRF、点击劫持、供应链攻击、Cookie 安全、CORS 配置错误、依赖漏洞——背后是同一个防御原则:对用户输入零信任,对输出内容强制编码,对第三方资源完整性校验。

防御清单的执行优先级:XSS > 供应链 > CSRF > 点击劫持。XSS 的防御成本最低(DOMPurify + CSP + 避免 innerHTML),覆盖的攻击面最广;供应链攻击的防御成本中等(SRI + lockfile + npm audit),但一旦被攻破影响范围最大。建议每季度进行一次安全审计,将上述检查脚本集成到 CI 流水线中,确保每次提交都经过安全门禁。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/28 14:03:59

【微服务】——docker hub推送镜像

一、前言 DockerHub 是一个由 Docker 公司运行和管理的基于云的存储库。它是一个在线存储库&#xff0c;Docker 镜像可以由其他用户发布和使用。有两种库&#xff1a;公共存储库和私有存储库。 docker images &#xff03;查看本机docker镜像列表 docker run -it <image n…

作者头像 李华
网站建设 2026/7/28 14:03:31

【LeetCode题解】147. 对链表进行插入排序

对链表进行插入排序。插入排序算法&#xff1a;插入排序是迭代的&#xff0c;每次只移动一个元素&#xff0c;直到所有元素可以形成一个有序的输出列表。 每次迭代中&#xff0c;插入排序只从输入数据中移除一个待排序的元素&#xff0c;找到它在序列中适当的位置&#xff0c;并…

作者头像 李华
网站建设 2026/7/28 14:03:04

MySQL数据库知识

MySQL MySQL 是一种关系型数据库,并且是开源免费的&#xff0c;方便扩展。MySQL是开放源代码的&#xff0c;任何人都可以在 GPL(General Public License) 的许可下下载并根据个性化的需要对其进行修改。MySQL的默认端口号是3306。 事务相关 定义&#xff1a;事务是逻辑上的一组…

作者头像 李华
网站建设 2026/7/28 14:01:18

AI与大模型新闻日报 | 2026-07-28

AI与大模型新闻日报20260728大模型技术共 11 条新闻1. 超维动力携手北大医疗&#xff1a;务实构建具身智能医疗落地路径来源: 量子位时间: 2026-07-27 09:55摘要: 一次技术与场景的深度耦合2. 上海青浦与华为共建&#xff0c;长三角 AI 联合创新中心正式启用来源: IT 之家时间:…

作者头像 李华
网站建设 2026/7/28 13:58:13

Switch-Toolbox:免费开源的游戏文件编辑神器,支持50+任天堂格式

Switch-Toolbox&#xff1a;免费开源的游戏文件编辑神器&#xff0c;支持50任天堂格式 【免费下载链接】Switch-Toolbox A tool to edit many video game file formats 项目地址: https://gitcode.com/gh_mirrors/sw/Switch-Toolbox 你是否曾梦想修改自己喜爱的任天堂游…

作者头像 李华