Web安全防护最佳实践
Web 安全是每个开发者都必须重视的课题,本文涵盖常见攻击方式和防护方案。
XSS 跨站脚本攻击
攻击者注入恶意脚本到页面中:
javascript
// 危险:直接插入未转义的HTML
element.innerHTML = userInput;
// 安全:使用 textContent
element.textContent = userInput;
// 安全:使用框架自动转义(React/Vue默认转义)
<div>{userInput}</div>
// 安全:需要HTML时使用白名单过滤
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);CSP 内容安全策略
nginx
# Nginx 配置 CSP 头
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.example.com;";CSRF 跨站请求伪造
javascript
// 使用 SameSite Cookie
app.use(session({
secret: 'secret-key',
cookie: {
httpOnly: true,
secure: true, // 仅 HTTPS
sameSite: 'strict', // 或 'lax'
}
}));
// CSRF Token
const csrf = require('csurf');
app.use(csrf({ cookie: true }));
// 前端获取 token
fetch('/api/csrf-token')
.then(res => res.json())
.then(({ csrfToken }) => {
// 后续请求带上 token
fetch('/api/data', {
headers: { 'X-CSRF-Token': csrfToken },
method: 'POST'
});
});SQL 注入
javascript
// 危险:字符串拼接
const query = `SELECT * FROM users WHERE name = '${name}'`;
// 安全:参数化查询
const query = 'SELECT * FROM users WHERE name = ?';
db.query(query, [name]);
// 安全:ORM
const user = await User.findOne({ where: { name } });安全 HTTP 头
javascript
// 使用 helmet 中间件(Express)
const helmet = require('helmet');
app.use(helmet());
// 或手动设置
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
next();
});密码安全
javascript
import bcrypt from 'bcrypt';
// 哈希密码(不要用 MD5/SHA1)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(password, saltRounds);
// 验证密码
const isValid = await bcrypt.compare(inputPassword, hashedPassword);
// 密码强度验证
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*d)(?=.*[@$!%*?&])[A-Za-zd@$!%*?&]{8,}$/;
if (!passwordRegex.test(password)) {
throw new Error('密码至少8位,包含大小写字母、数字和特殊字符');
}JWT 安全
javascript
// 生成 JWT
const token = jwt.sign(
{ userId: user.id, role: user.role },
process.env.JWT_SECRET,
{
expiresIn: '1h',
issuer: 'starr',
audience: 'starr-users'
}
);
// 安全存储:使用 httpOnly cookie 而非 localStorage
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 3600000
});速率限制
javascript
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15分钟
max: 100, // 每个IP最多100次请求
message: '请求过于频繁,请稍后再试'
});
app.use('/api/', limiter);
// 登录接口更严格限制
const loginLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1小时
max: 5, // 最多5次尝试
});
app.use('/api/login', loginLimiter);安全检查清单
- [ ] 所有输入进行验证和转义
- [ ] 使用 HTTPS 并启用 HSTS
- [ ] 设置安全 HTTP 头
- [ ] Cookie 设置 httpOnly、secure、sameSite
- [ ] 密码使用 bcrypt 哈希存储
- [ ] API 启用速率限制
- [ ] 定期更新依赖库
- [ ] 敏感数据不在日志中记录
总结
Web 安全是系统工程,需要从输入验证、输出编码、传输加密、认证授权多个层面防护。最关键的是:永远不信任用户输入,所有输入都需验证和转义。使用 helmet、bcrypt、CSP 等工具可以快速提升安全基线。



评论 2