前端不仅是美化页面或提升用户体验,更承担着保护用户数据和系统安全的重要责任。每一次表单提交、接口请求或动态交互,都可能成为攻击入口。前端开发者必须关注网络安全,如防止 XSS、CSRF、数据泄露等风险,设计安全的输入验证、权限控制和加密传输,确保应用既好看又安全,为用户和企业提供可靠保障。
1. XSS(Cross-Site Scripting)—— 类型与底层防护
1.1 三类 XSS 概览(一句话理解)
- 反射型(Reflected) :恶意输入随请求被服务器“反射”到响应并执行。
- 存储型(Stored) :恶意载体存储在数据库 / 评论 / 用户资料等,后续被其他用户触发。
- DOM-based:漏洞完全在客户端 JS 层(例如直接将
location.hash写入innerHTML)。
官方参考:OWASP XSS
1.2 攻击链原理图
1.3 底层防护原则(按优先级)
- 输出编码(Output Encoding) :上下文敏感编码是最根本防线。使用成熟库,如 lodash.escape。
- 避免危险 API:尽量不要用
innerHTML、document.write、eval()、new Function()。 - 安全模板 / 自动转义:现代框架(React/Vue/Angular)默认转义插值,避免使用
v-html、dangerouslySetInnerHTML。 - CSP(内容安全策略)做第二道防线:禁止 inline script、限制脚本来源、使用 nonce/hash。官方文档:MDN CSP
1.4 上下文敏感编码对比表
| 写入上下文 | 错误做法 | 正确防护 |
|---|---|---|
| HTML 内容 | el.innerHTML = user | el.textContent = user 或服务端 HTML 编码 |
| HTML 属性 | el.setAttribute('title', user) | 使用属性编码函数 |
| JS 字符串 | eval("..."+user) | JS-String-encode 或避免拼接 |
| URL | 直接拼接 query | encodeURIComponent(user) |
1.5 实战代码片段
Node 服务器端 HTML 转义:
const escape = require('lodash.escape');
res.send(`<div>欢迎 ${escape(username)}</div>`);
客户端避免 DOM XSS:
<div id="out"></div>
<script>
const text = decodeURIComponent(location.hash.slice(1) || '');
document.getElementById('out').textContent = text;
</script>
2. CSRF(Cross-Site Request Forgery)
2.1 原理图
2.2 防护策略
- SameSite Cookie:设置
SameSite=Lax或Strict。MDN 官方文档 - Anti-CSRF Token:服务器保存随机 token,前端提交时校验。官方指南:OWASP CSRF
- 验证 Origin / Referer:检查请求头来源。官方文档:MDN HTTP Origin
- 高风险操作二次确认:密码、2FA 等。
2.3 实战示例(Express + Fetch)
res.cookie('sid', sid, {
httpOnly: true,
secure: true,
sameSite: 'lax'
});
// server 渲染页面时注入 token
res.render('index', { csrfToken: req.csrfToken() });
// client fetch 请求
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
},
body: JSON.stringify({ amount: 100 })
});
3. 点击劫持(Clickjacking)
3.1 原理图
flowchart LR
A[恶意页面] -->|嵌入 victim.com iframe| B[victim.com]
A --> C[透明遮罩/按钮置换]
C --> D[用户点击]
D -->|实际触发| B[iframe 内按钮]
3.2 防护头
- CSP frame-ancestors:现代首选,灵活。MDN CSP frame-ancestors
- X-Frame-Options:兼容旧浏览器,值
DENY或SAMEORIGIN。MDN X-Frame-Options
示例:
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none';
4. 依赖安全(SCA / Supply-Chain)
4.1 风险点
- npm 包数量庞大,维护者被接管或发布恶意代码。
- 许可证合规问题可能引发法律风险。
官方指南:Snyk npm 安全最佳实践
4.2 CI 集成流程
- PR 阶段运行 SCA(Snyk / Dependabot / npm audit)。
- 使用 Lockfile 并校验未被篡改。
- 关键依赖使用私有 registry 或缓存代理。
- 维护 SBOM(Software Bill of Materials)。
- 手动审查关键依赖源码、提交、issue 活跃度。
4.3 工具示例
- Dependabot(GitHub)
- Snyk
- npm audit / audit-ci
GitHub Actions 示例(Snyk):
name: Snyk Scan
on: [push, pull_request]
jobs:
snyk:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Snyk to check for vulnerabilities
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
5. 常用安全 HTTP 头与 Cookie 基线
| Header | 目的 | 建议值 / 备注 |
|---|---|---|
| Content-Security-Policy | 限制内容来源、阻止 inline script | 使用 nonce/hash |
| X-Frame-Options | 防止 iframe 嵌入 | DENY / SAMEORIGIN |
| X-Content-Type-Options | 防止 MIME sniffing | nosniff |
| Strict-Transport-Security | 强制 HTTPS | max-age=...; includeSubDomains; preload |
| Referrer-Policy | 控制 Referer | no-referrer-when-downgrade |
| Permissions-Policy | 限制浏览器 API | geolocation=(), microphone=() |
Cookie 示例:
Set-Cookie: sid=...; HttpOnly; Secure; SameSite=Lax; Path=/
官方文档:MDN Set-Cookie
6. Checklist & PR 审查要点
- 输出编码是否做上下文敏感处理?
- 禁止危险 API / innerHTML / v-html / dangerouslySetInnerHTML?
- CSP、X-Frame-Options、frame-ancestors 是否配置?
- Cookie: HttpOnly, Secure, SameSite 是否设置?
- 依赖安全(Snyk / Dependabot / npm audit)集成 CI?
- Lockfile 是否校验?SBOM 是否保存?
- 异常监控 / CSP 报告 / WAF 日志是否接入?