前端安全¶
📚 章节目标¶
本章节将全面介绍前端安全的核心概念和技术,包括XSS、CSRF、CSP、安全最佳实践等,帮助学习者掌握前端安全的核心方法。
学习目标¶
- 理解前端安全的核心概念
- 掌握XSS攻击防护
- 掌握CSRF攻击防护
- 掌握CSP内容安全策略
- 理解前端安全最佳实践
- 掌握安全审计和测试
🔒 前端安全概述¶
1. 常见安全威胁¶
JavaScript
// 前端安全威胁
// 1. XSS (Cross-Site Scripting) - 跨站脚本攻击
// 2. CSRF (Cross-Site Request Forgery) - 跨站请求伪造
// 3. 点击劫持 - 恶意网站覆盖正常网站
// 4. 中间人攻击 - 拦截和修改通信
// 5. 数据泄露 - 敏感数据泄露
// 安全原则
// 1. 永远不要信任用户输入
// 2. 对所有输入进行验证和转义
// 3. 使用HTTPS加密通信
// 4. 实施最小权限原则
// 5. 定期进行安全审计
2. 安全检查清单¶
JavaScript
// 前端安全检查清单
const securityChecklist = {
// 输入验证
inputValidation: [
'验证所有用户输入',
'限制输入长度',
'使用白名单验证',
],
// 输出编码
outputEncoding: [
'对HTML输出进行编码',
'对JavaScript输出进行编码',
'对URL输出进行编码',
],
// 认证和授权
auth: [
'使用强密码策略',
'实施多因素认证',
'定期更新会话令牌',
],
// 通信安全
communication: [
'使用HTTPS',
'实施CSP',
'使用安全的Cookie',
],
// 数据保护
dataProtection: [
'加密敏感数据',
'不在本地存储敏感信息',
'实施数据最小化原则',
],
};
🎭 XSS攻击防护¶
1. XSS攻击类型¶
1.1 存储型XSS¶
JavaScript
// 存储型XSS示例
// 恶意用户提交包含脚本的评论
const comment = '<script>alert("XSS")</script>';
// 服务器存储评论
database.saveComment(comment);
// 其他用户查看评论时执行脚本
function renderComment(comment) {
// 不安全的渲染
document.getElementById('comments').innerHTML = comment;
}
// 防护:对输出进行编码
function renderComment(comment) {
const encoded = encodeHTML(comment);
document.getElementById('comments').innerHTML = encoded;
}
function encodeHTML(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
1.2 反射型XSS¶
JavaScript
// 反射型XSS示例
// URL参数包含恶意脚本
// http://example.com/search?q=<script>alert("XSS")</script>
// 服务器直接输出参数
function renderSearch(query) {
// 不安全的渲染
document.getElementById('results').innerHTML = `Search results for: ${query}`;
}
// 防护:对输出进行编码
function renderSearch(query) {
const encoded = encodeHTML(query);
document.getElementById('results').innerHTML = `Search results for: ${encoded}`;
}
1.3 DOM型XSS¶
JavaScript
// DOM型XSS示例
// 恶意URL
// http://example.com/#<img src=x onerror=alert("XSS")>
// JavaScript使用location.hash
const hash = window.location.hash;
document.getElementById('content').innerHTML = hash;
// 防护:对输出进行编码
const hash = window.location.hash;
const encoded = encodeHTML(hash);
document.getElementById('content').innerHTML = encoded;
2. XSS防护策略¶
2.1 输入验证¶
JavaScript
// 输入验证
function validateInput(input, type) {
const patterns = {
email: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
url: /^https?:\/\/.+/,
username: /^[a-zA-Z0-9_]{3,20}$/,
};
return patterns[type]?.test(input) || false; // ?.可选链:对象为null/undefined时安全返回undefined
}
// 使用示例
const email = 'user@example.com';
if (validateInput(email, 'email')) {
console.log('Valid email');
}
2.2 输出编码¶
JavaScript
// 使用DOMPurify进行HTML净化
import DOMPurify from 'dompurify';
function sanitizeHTML(dirty) {
return DOMPurify.sanitize(dirty);
}
// 使用示例
const dirty = '<script>alert("XSS")</script><p>Hello</p>';
const clean = sanitizeHTML(dirty);
console.log(clean); // <p>Hello</p>
// React自动转义
function Comment({ text }) {
return <div>{text}</div>; // 自动转义
}
// Vue自动转义
<template>
<div>{{ text }}</div> <!-- 自动转义 -->
</template>
2.3 CSP策略¶
JavaScript
// 设置CSP头
// Express.js — 使用nonce代替unsafe-inline(更安全)
const crypto = require('crypto');
app.use((req, res, next) => {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;
res.setHeader(
'Content-Security-Policy',
`default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'nonce-${nonce}'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; frame-ancestors 'none';`
);
next();
});
// ⚠️ 避免使用 'unsafe-inline' 和 'unsafe-eval',它们会严重削弱CSP对XSS的防护
// HTML meta标签(生产环境建议通过HTTP头设置)
<meta http-equiv="Content-Security-Policy" content="
default-src 'self';
script-src 'self';
style-src 'self';
img-src 'self' data: https:;
font-src 'self' data:;
connect-src 'self' https:;
frame-ancestors 'none';
">
🛡️ CSRF攻击防护¶
1. CSRF攻击原理¶
JavaScript
// CSRF攻击示例
// 用户登录银行网站
// https://bank.example.com/login
// 用户访问恶意网站
// 恶意网站包含隐藏表单
<form action="https://bank.example.com/transfer" method="POST">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="10000">
</form>
<script>
document.forms[0].submit();
</script>
// 用户浏览器自动提交表单
// 银行网站认为这是用户的合法请求
2. CSRF防护策略¶
2.1 CSRF Token¶
JavaScript
// 生成CSRF Token
import crypto from 'crypto';
function generateCSRFToken() {
return crypto.randomBytes(32).toString('hex');
}
// 服务器设置Token
app.use((req, res, next) => {
const token = generateCSRFToken();
res.cookie('csrfToken', token, {
httpOnly: false, // Double Submit Cookie模式需要前端JS读取,不能设为httpOnly
secure: true,
sameSite: 'strict',
});
req.csrfToken = token;
next();
});
// 验证Token
function validateCSRFToken(req, res, next) {
const token = req.cookies.csrfToken;
const headerToken = req.headers['x-csrf-token'];
if (token && headerToken && token === headerToken) {
next();
} else {
res.status(403).json({ error: 'Invalid CSRF token' });
}
}
// 前端发送Token
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': getCookie('csrfToken'),
},
body: JSON.stringify({ to: 'user', amount: 100 }),
});
2.2 SameSite Cookie¶
JavaScript
// 设置SameSite Cookie
app.use(session({
secret: 'secret',
cookie: {
httpOnly: true,
secure: true,
sameSite: 'strict', // 'strict' | 'lax' | 'none'
},
}));
// SameSite选项
// strict - 仅同站请求发送Cookie
// lax - 同站请求和顶级导航发送Cookie
// none - 所有请求都发送Cookie(需要Secure)
2.3 验证来源¶
JavaScript
// 验证Referer头
function validateReferer(req, res, next) {
const referer = req.headers.referer;
const allowedOrigins = ['https://example.com'];
if (referer && allowedOrigins.some(origin => referer.startsWith(origin))) {
next();
} else {
res.status(403).json({ error: 'Invalid referer' });
}
}
// 验证Origin头
function validateOrigin(req, res, next) {
const origin = req.headers.origin;
const allowedOrigins = ['https://example.com'];
if (origin && allowedOrigins.includes(origin)) {
next();
} else {
res.status(403).json({ error: 'Invalid origin' });
}
}
🚪 其他安全威胁¶
1. 点击劫持防护¶
JavaScript
// 点击劫持攻击
// 恶意网站使用iframe嵌入正常网站
// 诱导用户点击隐藏的按钮
// 防护:使用X-Frame-Options头
app.use((req, res, next) => {
res.setHeader('X-Frame-Options', 'DENY');
// 或者
res.setHeader('X-Frame-Options', 'SAMEORIGIN');
next();
});
// 防护:使用CSP frame-ancestors
app.use((req, res, next) => {
res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
next();
});
// 防护:JavaScript检测
if (window.self !== window.top) {
window.top.location = window.self.location;
}
2. 中间人攻击防护¶
JavaScript
// 使用HTTPS
// 配置HTTPS服务器
const https = require('https');
const fs = require('fs');
const options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt'),
ca: fs.readFileSync('ca.crt'),
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('Hello HTTPS!');
}).listen(443);
// HSTS (HTTP Strict Transport Security)
app.use((req, res, next) => {
res.setHeader(
'Strict-Transport-Security',
'max-age=31536000; includeSubDomains; preload'
);
next();
});
3. 数据泄露防护¶
JavaScript
// 不在本地存储敏感信息
// 不好的做法
localStorage.setItem('password', 'secret123');
localStorage.setItem('token', 'abc123');
// 好的做法
// 使用HttpOnly Cookie
res.cookie('token', 'abc123', {
httpOnly: true,
secure: true,
sameSite: 'strict',
});
// 加密敏感数据
import crypto from 'crypto';
function encrypt(text, key) {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
let encrypted = cipher.update(text, 'utf8', 'hex');
encrypted += cipher.final('hex');
return iv.toString('hex') + ':' + encrypted;
}
function decrypt(text, key) {
const parts = text.split(':');
const iv = Buffer.from(parts[0], 'hex');
const encrypted = parts[1];
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
🔍 安全审计和测试¶
1. 安全审计工具¶
JavaScript
// 使用npm audit
npm audit
// 使用Snyk
npm install -g snyk
snyk test
// 使用OWASP ZAP
// 下载和运行OWASP ZAP
// 扫描应用程序
// 使用Burp Suite
// 下载和运行Burp Suite
// 代理和拦截请求
2. 安全测试¶
JavaScript
// XSS测试
function testXSS(input) {
const xssPayloads = [
'<script>alert("XSS")</script>',
'<img src=x onerror=alert("XSS")>',
'<svg onload=alert("XSS")>',
'javascript:alert("XSS")',
];
xssPayloads.forEach(payload => { // 箭头函数:简洁的函数语法
const result = sanitizeHTML(payload);
if (result !== payload) {
console.log(`XSS payload sanitized: ${payload}`);
} else {
console.error(`XSS payload not sanitized: ${payload}`);
}
});
}
// CSRF测试
function testCSRF() {
// 测试是否验证CSRF Token
// 测试是否验证Referer
// 测试是否使用SameSite Cookie
}
📝 练习题¶
1. 基础题¶
题目1:实现XSS防护
JavaScript
// 实现HTML编码函数
function encodeHTML(str) {
// 编码HTML特殊字符
}
// 使用示例
const input = '<script>alert("XSS")</script>'; // const不可重新赋值;let块级作用域变量
const encoded = encodeHTML(input);
console.log(encoded);
2. 进阶题¶
题目2:实现CSRF防护
JavaScript
// 生成CSRF Token
function generateCSRFToken() {
// 生成随机Token
}
// 验证CSRF Token
function validateCSRFToken(req) {
// 验证Token是否有效
}
3. 面试题¶
题目3:解释XSS和CSRF的区别
JavaScript
// 答案要点:
// XSS (Cross-Site Scripting):
// - 攻击者在网站中注入恶意脚本
// - 脚本在用户浏览器中执行
// - 可以窃取用户数据、执行恶意操作
// CSRF (Cross-Site Request Forgery):
// - 攻击者诱导用户发送请求
// - 请求使用用户的认证信息
// - 可以执行用户未授权的操作
// 防护:
// XSS - 输入验证、输出编码、CSP
// CSRF - CSRF Token、SameSite Cookie、验证来源
🎯 本章总结¶
本章节全面介绍了前端安全的核心概念和技术,包括XSS、CSRF、CSP、安全最佳实践等。关键要点:
- 安全威胁:理解常见的前端安全威胁
- XSS防护:掌握XSS攻击的防护策略
- CSRF防护:掌握CSRF攻击的防护策略
- 其他威胁:掌握点击劫持、中间人攻击、数据泄露的防护
- 安全审计:掌握安全审计和测试方法
- 最佳实践:理解前端安全最佳实践
下一步将深入学习前端架构设计。