前端安全加固:XSS、CSRF、CSP 防护实战

引言

在 Web 开发中,安全是不可或缺的一环。前端作为用户与服务器交互的第一道防线,承担着重要的安全职责。本文将深入讲解三种常见的前端安全威胁及其防护方案:XSS(跨站脚本攻击)、CSRF(跨站请求伪造)和 CSP(内容安全策略)。

一、XSS(跨站脚本攻击)

什么是 XSS

XSS 攻击是指攻击者向网页中注入恶意脚本,当其他用户浏览该页面时,脚本会在其浏览器中执行,从而窃取用户信息、劫持会话等。

XSS 的三种类型

反射型 XSS:恶意脚本通过 URL 参数传递,立即反射回页面

存储型 XSS:恶意脚本存储在服务器上(如评论区),每次加载时都被执行

DOM XSS:通过修改 DOM 树结构触发,不经过服务器

防护方案

1. 转义用户输入

javascript 复制代码
// 安全的 HTML 转义函数
function escapeHtml(text) {
  const htmlEntities = {
    '&': '&',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;'
  };
  return text.replace(/[&<>"']/g, char => htmlEntities[char]);
}

// 使用示例
const userInput = '<script>alert("XSS")</script>';
const safeOutput = escapeHtml(userInput);
// 输出:&lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

2. 使用 Content Security Policy (CSP)

css 复制代码
<!-- 在 HTML 头部添加 CSP 元标签 -->
<meta http-equiv="Content-Security-Policy" 
      content="default-src 'self'; 
               script-src 'self' https://trusted-cdn.com; 
               style-src 'self' 'unsafe-inline'; 
               img-src 'self' data: https:; 
               object-src 'none'; 
               base-uri 'self'; 
               form-action 'self';">

3. 避免危险的 DOM 操作

ini 复制代码
// ❌ 危险做法
element.innerHTML = userInput;

// ✅ 安全做法
element.textContent = userInput;

// 或者使用 DOM API
const textNode = document.createTextNode(userInput);
element.appendChild(textNode);

4. 使用现代框架的内置防护

React、Vue 等现代框架默认会对插值表达式进行转义:

javascript 复制代码
// React - 自动转义
function SafeComponent({ userInput }) {
  return <div>{userInput}</div>; // 安全
}

// ❌ 需要小心使用 dangerouslySetInnerHTML
function UnsafeComponent({ userInput }) {
  return <div dangerouslySetInnerHTML={{ __html: userInput }} />;
}

二、CSRF(跨站请求伪造)

什么是 CSRF

CSRF 攻击利用用户的登录状态,诱使用户在不知情的情况下执行非预期的操作,如转账、修改密码等。

攻击原理

  1. 用户登录网站 A,获得认证 Cookie
  2. 用户访问恶意网站 B
  3. 网站 B 包含指向网站 A 的请求(如 <img src="https://a.com/transfer?to=hacker&amount=1000">
  4. 浏览器自动携带网站 A 的 Cookie,请求被执行

防护方案

1. CSRF Token

javascript 复制代码
// 后端生成 token
app.get('/form', (req, res) => {
  const csrfToken = generateToken();
  res.cookie('csrfToken', csrfToken, { httpOnly: true });
  res.render('form', { csrfToken });
});

// 前端在请求中携带 token
fetch('/api/action', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': csrfToken,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(data)
});

// 后端验证 token
app.post('/api/action', (req, res) => {
  const token = req.headers['x-csrf-token'];
  if (!validateToken(token, req.cookies.csrfToken)) {
    return res.status(403).json({ error: 'CSRF token invalid' });
  }
  // 处理请求
});
php 复制代码
// 设置 Cookie 的 SameSite 属性
res.cookie('sessionId', session_id, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict' // 或 'lax'
});
  • strict: 完全禁止跨站请求携带 Cookie
  • lax: 允许部分安全的跨站请求(如 GET 导航)
  • none: 允许所有跨站请求(需要配合 secure)

3. 验证 Referer 头

javascript 复制代码
// 中间件验证 Referer
function checkReferer(req, res, next) {
  const referer = req.headers.referer;
  const allowedDomains = ['https://yourdomain.com'];
  
  if (!referer || !allowedDomains.some(domain => referer.startsWith(domain))) {
    return res.status(403).json({ error: 'Invalid referer' });
  }
  next();
}

app.post('/api/action', checkReferer, (req, res) => {
  // 处理请求
});

三、CSP(内容安全策略)

CSP 的作用

CSP 通过白名单机制,控制浏览器可以加载和执行哪些资源,是防御 XSS 的最后一道防线。

常用指令

指令 说明 示例
default-src 默认策略 default-src 'self'
script-src 脚本来源 script-src 'self' https://cdn.example.com
style-src 样式来源 style-src 'self' 'unsafe-inline'
img-src 图片来源 img-src 'self' data: https:
connect-src 连接来源 connect-src 'self' https://api.example.com
font-src 字体来源 font-src 'self' https://fonts.googleapis.com
object-src 插件来源 object-src 'none'
base-uri base 标签目标 base-uri 'self'
form-action 表单提交目标 form-action 'self'

完整示例

css 复制代码
<!-- 通过 HTTP 响应头设置 -->
<!-- Content-Security-Policy: 
  default-src 'self';
  script-src 'self' 'unsafe-inline' https://cdn.example.com;
  style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
  img-src 'self' data: https:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com;
  object-src 'none';
  base-uri 'self';
  form-action 'self';
  frame-ancestors 'none';
  upgrade-insecure-requests;
-->

开发阶段:CSP 报告

xml 复制代码
<!-- 启用 CSP 报告 -->
<meta http-equiv="Content-Security-Policy-Report-Only" 
      content="default-src 'self'; report-uri /csp-report">

<!-- 后端接收报告 -->
app.post('/csp-report', (req, res) => {
  const report = req.body;
  console.log('CSP Violation:', report);
  // 记录到日志系统
  res.status(204).send();
});

四、综合防护实践

1. 安全 Headers 配置(Express 示例)

php 复制代码
const helmet = require('helmet');

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "https://cdn.example.com"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", "data:", "https:"],
      connectSrc: ["'self'", "https://api.example.com"],
      fontSrc: ["'self'"],
      objectSrc: ["'none'"],
      baseUri: ["'self'"],
      formAction: ["'self'"],
      frameAncestors: ["'none'"]
    }
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  },
  xssFilter: true,
  noSniff: true,
  referrerPolicy: { policy: "strict-origin-when-cross-origin" }
}));

2. 输入验证与输出编码

javascript 复制代码
// 输入验证
function validateInput(input, rules) {
  for (const [field, rule] of Object.entries(rules)) {
    if (!rule.test(input[field])) {
      throw new Error(`Invalid ${field}`);
    }
  }
  return input;
}

// 输出编码函数库
const encode = {
  html: (str) => str.replace(/[&<>"']/g, c => 
    ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c])
  ),
  url: (str) => encodeURIComponent(str),
  json: (str) => JSON.stringify(str)
};

总结

前端安全是一个系统工程,需要多层防护:

  1. XSS 防护:转义输入、使用 CSP、避免危险 DOM 操作
  2. CSRF 防护:使用 Token、设置 SameSite Cookie、验证 Referer
  3. CSP 策略:建立资源白名单,限制可执行内容

记住安全原则:

  • 永远不要信任客户端输入
  • 默认拒绝,显式允许
  • 纵深防御,多层防护

通过合理配置和持续监控,可以大幅降低前端安全风险,保护用户数据和系统安全。

相关推荐
momo(激进版)1 小时前
mathjs使用简记
前端·javascript
JarvanMo1 小时前
7 个开源 iOS 应用,让你成为更好的开发者
前端·ios
jjw_zyfx1 小时前
css 点击显示并移动元素,再次点击移回元素并消失
前端·javascript·css
虎子_layor1 小时前
Headless Chrome 该退休了?Obscura 正在给 AI Agent 换浏览器底座
前端·人工智能·后端
深海鱼在掘金1 小时前
Next.js从入门到实战保姆级教程(第六章):服务端组件与客户端组件
前端·typescript·next.js
HookJames2 小时前
Turnkey PCBA - Hero
前端·php
深海鱼在掘金2 小时前
Next.js从入门到实战保姆级教程(第十章):表单处理与 Server Actions
前端·typescript·next.js
深海鱼在掘金2 小时前
Next.js从入门到实战保姆级教程(第九章):元数据与 SEO 优化
前端·typescript·next.js
сокол2 小时前
【网安-Web渗透测试-Linux提权】SUID提权
linux·前端·web安全·网络安全