攻击与防御思维
Web 安全的黄金法则:永远不要信任客户端输入。所有从客户端接收的数据都必须经过验证、过滤、转义后才能使用。
1. XSS(跨站脚本攻击)
反射型 XSS
// 攻击者注入
https://example.com/search?q=<script>alert(document.cookie)</script>
// 防御:输出转义
const escapeHtml = (str) =>
str.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"');
存储型 XSS
攻击脚本被持久化到数据库,每次加载页面时执行。防御手段:
// 后端:输入过滤 + 输出转义
function sanitize(input) {
return input.replace(/[<>]|[\u0000-\u001F]/g, '');
}
// 前端:React 默认转义
<div>{userInput}</div> // 安全:React 自动转义
<div dangerouslySetInnerHTML={{__html: userInput}} /> // 危险!必须先用 DOMPurify 清洗
CSP 内容安全策略
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-随机值'; style-src 'self' 'unsafe-inline';
2. CSRF(跨站请求伪造)
// 攻击:诱导用户点击恶意链接
<img src="https://bank.com/transfer?to=hacker&amount=10000" />
// 防御 1:SameSite Cookie
Set-Cookie: session=xxx; SameSite=Lax; Secure; HttpOnly
// 防御 2:CSRF Token
<form>
<input type="hidden" name="_csrf" value="{{ token }}" />
</form>
// 防御 3:验证 Referer/Origin 头
const origin = req.headers.origin || req.headers.referer;
if (!allowedOrigins.has(origin)) return 403;
3. SQL 注入
// 攻击示例
// username = "admin' --"
SELECT * FROM users WHERE username = 'admin' --' AND password = 'xxx'
// 防御 1:参数化查询
const stmt = db.prepare('SELECT * FROM users WHERE username = ? AND password = ?');
stmt.execute(username, password); // 自动转义
// 防御 2:ORM 使用
const user = await User.findOne({ where: { username, password } });
4. 安全响应头一览
// Nginx 配置
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
总结
Web 安全的攻防是永恒的话题。掌握 XSS、CSRF、SQL 注入的原理与多层防御手段,是每个后端和前端开发者的必修课。