前端安全攻防实战

217 阅读5分钟

引言:安全不是后补的,而是设计出来的

在现代 Web 开发中,前端已经不仅仅是 UI 层的展示工具,它承担了越来越多的业务逻辑和数据处理职责。然而,随着功能复杂度的提升,前端面临的安全风险也日益增加。

本文将从常见 Web 安全漏洞的底层原理出发,深入讲解内容安全策略(Content Security Policy, CSP)的高级配置技巧,并结合实际项目场景,探讨前端加密与认证的最佳实践,帮助你在构建应用时就具备防御意识。


一、常见 Web 安全漏洞原理剖析

1. XSS(跨站脚本攻击)

XSS 是最经典的前端安全漏洞之一,攻击者通过向页面注入恶意脚本,在用户浏览器中执行非预期的操作。

攻击类型:

  • 反射型 XSS:攻击载荷包含在 URL 中,诱导用户点击。
  • 存储型 XSS:恶意脚本被存储到服务器,如评论区、留言板等。
  • DOM 型 XSS:攻击完全发生在前端,不经过服务器。
<!-- 恶意示例 -->
<script>
  document.write('<img src=x onerror=eval("malicious code")>');
</script>

防御手段:

  • 输入过滤(HTML 编码);
  • 输出转义(使用 DOMPurify 等库);
  • 启用 CSP(后续章节详述)[[4]]。

2. CSRF(跨站请求伪造)

CSRF 利用用户的登录状态,诱导其访问攻击者控制的网站,从而发起对目标站点的伪造请求。

攻击示例:

<img src="https://bank.com/transfer?to=hacker&amount=1000" />

如果用户此时正登录银行系统,且未做 Token 校验,则可能完成转账操作。

防御方式:

  • 使用 SameSite Cookie 属性;
  • 添加 CSRF Token 并进行验证;
  • 前端设置 Origin 检查[[6]]。

3. SSRF(服务端请求伪造)

虽然 SSRF 更常被认为是后端漏洞,但当前端调用后端接口时,若参数未严格校验,也可能成为攻击入口。

例如,一个“预览图片”功能允许传入任意 URL,攻击者可借此探测内网资源。

防御建议:

  • 前端限制输入格式;
  • 后端对目标地址进行白名单校验;
  • 不暴露内部服务给外部访问[[7]]。

4. Clickjacking(点击劫持)

攻击者通过透明 iframe 覆盖在正常按钮上,诱使用户误点执行恶意操作。

防御方式:

  • 设置 X-Frame-OptionsContent-Security-Policyframe-ancestors 指令;
  • 在关键操作前添加二次确认[[5]]。

二、CSP 策略的深度配置

Content Security Policy(CSP)是浏览器提供的强大安全机制,用于防止 XSS、数据泄露等攻击。

1. CSP 基本语法

Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none';
  • default-src:默认策略;
  • script-src:允许加载的脚本源;
  • object-src:是否允许 <object><embed>
  • style-srcimg-srcconnect-src:分别控制样式、图片、网络请求等[[4]]。

2. CSP 进阶配置技巧

(1)nonce-based 白名单

允许特定 inline 脚本执行:

Content-Security-Policy: script-src 'nonce-abc123';
<script nonce="abc123">
  // 只有带匹配 nonce 的脚本可以执行
</script>

适用于必须 inline 执行的初始化代码。

(2)strict-dynamic 动态信任链

允许动态生成的脚本继承信任关系:

Content-Security-Policy: script-src 'strict-dynamic';

这对于模块化加载或依赖第三方脚本的项目非常有用[[8]]。

(3)report-uri / report-to:错误上报机制

启用 CSP 日志收集,便于监控潜在攻击行为:

Content-Security-Policy: ...; report-uri /csp-violation-report-endpoint;

你可以搭建自己的 CSP 上报服务器,实时追踪非法脚本注入尝试[[9]]。


三、前端加密与认证的最佳实践

1. 密码传输加密

HTTPS 是基础

所有通信必须启用 HTTPS,否则任何加密都形同虚设。

密码哈希处理

密码不应以明文形式提交,而应在客户端进行哈希处理后再发送:

async function hashPassword(password: string) {
  const encoder = new TextEncoder();
  const hashBuffer = await crypto.subtle.digest('SHA-256', encoder.encode(password));
  return Array.from(new Uint8Array(hashBuffer)).map(b => b.toString(16).padStart(2, '0')).join('');
}

注意:这只是增强安全性的一环,最终仍需后端再次哈希存储[[2]]。


2. JWT 认证机制

JSON Web Token(JWT)是目前主流的身份认证方案之一。

使用流程:

  1. 用户登录,后端返回带有签名的 token;
  2. 前端保存至 localStorage 或内存中;
  3. 请求时携带 Authorization: Bearer <token>
  4. 后端验证签名合法性。

安全建议:

  • 使用 HTTPS;
  • 设置合理的过期时间;
  • 存储避免使用 localStorage,推荐内存缓存 + 自动刷新机制;
  • 实现 logout 清除 token,并加入黑名单[[10]]。

3. OAuth 2.0 第三方登录

OAuth 2.0 是开放授权协议,广泛用于社交登录、API 授权等场景。

常见模式:

  • Authorization Code(推荐)
  • Implicit(已逐步淘汰)
  • PKCE(移动端专用)

安全建议:

  • 使用 state 参数防止 CSRF;
  • 使用 PKCE 提高移动端安全性;
  • 回调页应设置固定路径,防止 open redirect[[1]]。

4. 前端加密敏感数据(如聊天记录)

对于需要高度保密的数据(如聊天、私信),可考虑使用前端加密再上传:

// AES 加密示例
async function encrypt(data: string, key: CryptoKey) {
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const encoded = new TextEncoder().encode(data);
  const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, encoded);
  return { iv: arrayBufferToBase64(iv), data: arrayBufferToBase64(encrypted) };
}

注意:加密密钥应由服务端管理,或使用 Diffie-Hellman 协议协商[[2]]。


四、结语:前端安全不是一个人的战斗

前端安全是一个系统工程,需要前后端协同作战。你不能指望一个 CSP 就能挡住所有攻击,也不能只靠 HTTPS 来保证通信安全。