引言:安全不是后补的,而是设计出来的
在现代 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-Options或Content-Security-Policy的frame-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-src、img-src、connect-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)是目前主流的身份认证方案之一。
使用流程:
- 用户登录,后端返回带有签名的 token;
- 前端保存至 localStorage 或内存中;
- 请求时携带
Authorization: Bearer <token>; - 后端验证签名合法性。
安全建议:
- 使用 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 来保证通信安全。