前端安全防护完全指南
本文深入探讨前端开发中的常见安全问题,并提供全面的防护策略和最佳实践,帮助开发者构建更安全的 Web 应用。
安全威胁概述
graph TD
A[前端安全威胁] --> B[XSS攻击]
A --> C[CSRF攻击]
A --> D[点击劫持]
B --> E[反射型XSS]
B --> F[存储型XSS]
B --> G[DOM型XSS]
C --> H[GET类型CSRF]
C --> I[POST类型CSRF]
D --> J[UI覆盖]
D --> K[透明iframe]
1. 跨站脚本攻击(XSS)
1.1 XSS 类型及原理
反射型 XSS
- 非持久性攻击
- 通过 URL 参数注入恶意代码
- 服务端未经处理直接返回用户输入
sequenceDiagram
participant U as 用户
participant A as 攻击者
participant B as 浏览器
participant S as 服务器
A->>U: 1. 发送恶意链接
U->>B: 2. 点击链接
B->>S: 3. 发送请求(带有恶意代码)
S->>B: 4. 响应(包含恶意代码)
B->>B: 5. 执行恶意代码
B->>A: 6. 发送用户数据
// 危险的URL示例
https://example.com/search?q=<script>alert('XSS')</script>
// 服务端不安全的处理
app.get('/search', (req, res) => {
res.send(`搜索结果: ${req.query.q}`); // 直接输出用户输入
});存储型 XSS
- 持久性攻击
- 恶意代码存储在数据库中
- 其他用户访问页面时触发攻击
sequenceDiagram
participant A as 攻击者
participant B1 as 攻击者浏览器
participant S as 服务器
participant DB as 数据库
participant B2 as 用户浏览器
participant U as 用户
A->>B1: 1. 输入恶意代码
B1->>S: 2. 提交数据
S->>DB: 3. 存储恶意代码
U->>B2: 4. 访问页面
B2->>S: 5. 请求数据
S->>DB: 6. 读取数据
DB->>S: 7. 返回含恶意代码的数据
S->>B2: 8. 响应
B2->>B2: 9. 执行恶意代码
B2->>A: 10. 发送用户数据
// 危险的评论输入
const comment = '<script>steal(document.cookie)</script>';
// 数据库中存储的恶意脚本
{
"comment": "<script>steal(document.cookie)</script>",
"user": "attacker"
}DOM 型 XSS
- 前端 JavaScript 直接使用不可信数据
- 修改 DOM 结构触发攻击
- 不经过服务端
sequenceDiagram
participant A as 攻击者
participant U as 用户
participant B as 浏览器
participant D as DOM
A->>U: 1. 提供恶意URL
U->>B: 2. 访问URL
B->>D: 3. JavaScript处理URL参数
D->>D: 4. 修改DOM
D->>B: 5. 执行恶意代码
B->>A: 6. 发送用户数据
// 危险的 DOM 操作
document.getElementById('content').innerHTML = location.hash.substring(1);1.2 XSS 防护措施
输入验证和净化
// 使用 DOMPurify 净化用户输入
import DOMPurify from 'dompurify';
const clean = DOMPurify.sanitize(userInput, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong'],
ALLOWED_ATTR: ['title']
});输出编码
// HTML 转义函数
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// React 自动转义
const UserInput = ({ data }) => <div>{data}</div>;CSP 配置
<!-- 内容安全策略配置 -->
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';
script-src 'self' 'unsafe-inline' 'unsafe-eval';
style-src 'self' 'unsafe-inline';">2. 跨站请求伪造(CSRF)
2.1 攻击原理
- 利用用户已登录的身份
- 在第三方网站发起请求
- 自动携带目标站点的 Cookie
sequenceDiagram
participant U as 用户
participant B as 浏览器
participant T as 目标网站
participant A as 攻击者网站
U->>B: 1. 登录目标网站
B->>T: 2. 身份验证
T->>B: 3. 设置Cookie
U->>B: 4. 访问攻击者网站
B->>A: 5. 加载攻击页面
A->>B: 6. 返回恶意表单/请求
B->>T: 7. 自动发送请求(带Cookie)
T->>B: 8. 执行操作
// 攻击者的恶意网站代码
<form action="https://bank.example.com/transfer" method="POST" id="stealMoney">
<input type="hidden" name="amount" value="10000">
<input type="hidden" name="to" value="attacker">
</form>
<script>document.getElementById('stealMoney').submit();</script>2.2 防护措施
Token 验证
// 服务端生成 token
const csrfToken = crypto.randomBytes(16).toString('hex');
// 前端请求携带 token
const headers = {
'X-CSRF-Token': csrfToken,
'Content-Type': 'application/json',
};
fetch('/api/data', {
method: 'POST',
headers,
credentials: 'include',
body: JSON.stringify(data)
});SameSite Cookie
// 设置 Cookie
Set-Cookie: sessionId=abc123; SameSite=Strict; Secure; HttpOnly3. 点击劫持
3.1 攻击原理
sequenceDiagram
participant U as 用户
participant B as 浏览器
participant A as 攻击者网站
participant T as 目标网站
U->>B: 1. 访问攻击者网站
B->>A: 2. 请求页面
A->>B: 3. 返回带透明iframe的页面
B->>T: 4. 加载目标网站(iframe)
T->>B: 5. 返回目标页面
B->>B: 6. 显示诱饰界面
U->>B: 7. 点击诱饰按钮
B->>T: 8. 触发目标操作
<!-- 攻击者的页面 -->
<style>
iframe {
width: 500px;
height: 500px;
position: absolute;
top: -100px;
left: -100px;
opacity: 0.0001;
z-index: 2;
}
.fake-button {
position: absolute;
top: 300px;
left: 300px;
z-index: 1;
}
</style>
<iframe src="https://victim-site.com/"></iframe>
<button class="fake-button">点击领取奖励</button>3.2 防护措施
sequenceDiagram
participant A as 攻击者网站
participant B as 浏览器
participant T as 受保护网站
A->>B: 1. 尝试嵌入iframe
B->>T: 2. 请求页面
T->>B: 3. 返回X-Frame-Options
Note over B: 4. 检查X-Frame-Options
B->>B: 5. 阻止iframe加载
Note over B: 6. 攻击失败
X-Frame-Options
// 服务端设置
response.setHeader('X-Frame-Options', 'SAMEORIGIN');CSP frame-ancestors
// 服务端设置
response.setHeader(
'Content-Security-Policy',
"frame-ancestors 'self' https://trusted-site.com"
);JavaScript 防护
// 判断当前网页是否被嵌入iframe
if (window.self !== window.top) {
window.top.location = window.self.location;
}4. 其他安全措施
4.1 安全的 Cookie 配置
// 设置安全的 Cookie
app.use(session({
cookie: {
secure: true, // 仅通过 HTTPS 传输
httpOnly: true, // 禁止 JavaScript 访问
sameSite: 'strict', // 严格的同源策略
maxAge: 3600000 // 有效期限
}
}));4.2 HTTPS 配置
// Node.js HTTPS 服务器配置
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('private-key.pem'),
cert: fs.readFileSync('certificate.pem'),
ciphers: [
"ECDHE-RSA-AES128-GCM-SHA256",
"ECDHE-ECDSA-AES128-GCM-SHA256"
].join(':')
};
https.createServer(options, app).listen(443);安全检查清单
-
XSS 防护
- 实施内容安全策略 (CSP)
- 对用户输入进行验证和净化
- 使用安全的模板引擎
- 对输出进行适当转义
-
CSRF 防护
- 实施 CSRF Token
- 配置 SameSite Cookie
- 验证请求来源
- 使用安全的 HTTP 方法
-
点击劫持防护
- 配置 X-Frame-Options
- 实施 frame-ancestors CSP
- 添加 JavaScript 防护层
-
通用安全措施
- 启用 HTTPS
- 配置安全的 Cookie
- 实施适当的访问控制
- 定期进行安全审计
参考资源
作者注
本文章首次发布于 2018 年 06 月 09 日,如有更新会在文末标注。如果您发现任何错误或有任何建议,欢迎在评论区留言或通过邮件联系我。
最后更新:2024 年 12 月 31 日
本文章遵循 CC BY-NC-SA 4.0 协议