安全最佳实践 #

一、安全概述 #

1.1 常见安全威胁 #

威胁 说明
XSS 跨站脚本攻击
CSRF 跨站请求伪造
SQL注入 恶意SQL代码注入
点击劫持 嵌入恶意iframe
中间人攻击 数据传输被窃听

1.2 安全原则 #

  • 最小权限原则
  • 输入验证
  • 输出编码
  • 使用HTTPS
  • 及时更新依赖

二、Helmet安全头 #

2.1 安装 #

bash
npm install helmet

2.2 基本使用 #

javascript
const helmet = require('helmet');
app.use(helmet());

2.3 单独配置 #

javascript
app.use(helmet.contentSecurityPolicy({
    directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'", "trusted-cdn.com"],
        styleSrc: ["'self'", "'unsafe-inline'"],
        imgSrc: ["'self'", "data:", "cdn.example.com"],
        connectSrc: ["'self'", "api.example.com"],
        fontSrc: ["'self'", "fonts.gstatic.com"],
        objectSrc: ["'none'"],
        frameSrc: ["'none'"],
        upgradeInsecureRequests: []
    }
}));

app.use(helmet.crossOriginEmbedderPolicy());
app.use(helmet.crossOriginOpenerPolicy());
app.use(helmet.crossOriginResourcePolicy({ policy: "same-origin" }));
app.use(helmet.dnsPrefetchControl({ allow: false }));
app.use(helmet.frameguard({ action: 'deny' }));
app.use(helmet.hidePoweredBy());
app.use(helmet.hsts({ maxAge: 31536000, includeSubDomains: true }));
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());
app.use(helmet.originAgentCluster());
app.use(helmet.permittedCrossDomainPolicies());
app.use(helmet.referrerPolicy({ policy: 'strict-origin-when-cross-origin' }));
app.use(helmet.xssFilter());

三、CSRF防护 #

3.1 安装csurf #

bash
npm install csurf cookie-parser

3.2 配置 #

javascript
const csrf = require('csurf');
const cookieParser = require('cookie-parser');

app.use(cookieParser());
app.use(csrf({ cookie: true }));

app.get('/api/csrf-token', (req, res) => {
    res.json({ csrfToken: req.csrfToken() });
});

app.post('/api/data', (req, res) => {
    res.json({ message: '成功' });
});

3.3 前端使用 #

javascript
fetch('/api/data', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': csrfToken
    },
    body: JSON.stringify(data)
});

四、XSS防护 #

4.1 输入验证 #

javascript
const validator = require('validator');

const sanitizeInput = (input) => {
    return validator.escape(input);
};

const validateEmail = (email) => {
    return validator.isEmail(email);
};

4.2 输出编码 #

javascript
const escapeHtml = (str) => {
    return str
        .replace(/&/g, '&')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#x27;');
};

4.3 Content Security Policy #

javascript
app.use(helmet.contentSecurityPolicy({
    directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'"],
        styleSrc: ["'self'", "'unsafe-inline'"],
        imgSrc: ["'self'", "data:"],
        connectSrc: ["'self'"],
        fontSrc: ["'self'"],
        objectSrc: ["'none'"],
        frameSrc: ["'none'"]
    }
}));

五、SQL注入防护 #

5.1 参数化查询 #

javascript
const [rows] = await pool.query(
    'SELECT * FROM users WHERE id = ?',
    [userId]
);

5.2 ORM使用 #

javascript
const user = await User.findOne({ where: { id: userId } });

5.3 输入验证 #

javascript
const { body, validationResult } = require('express-validator');

app.post('/users', [
    body('name').trim().escape(),
    body('email').isEmail().normalizeEmail()
], (req, res) => {
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
        return res.status(400).json({ errors: errors.array() });
    }
});

六、认证安全 #

6.1 密码哈希 #

javascript
const bcrypt = require('bcryptjs');

const hashPassword = async (password) => {
    const salt = await bcrypt.genSalt(10);
    return await bcrypt.hash(password, salt);
};

const comparePassword = async (password, hashedPassword) => {
    return await bcrypt.compare(password, hashedPassword);
};

6.2 JWT安全 #

javascript
const jwt = require('jsonwebtoken');

const generateToken = (userId) => {
    return jwt.sign(
        { id: userId },
        process.env.JWT_SECRET,
        { expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
    );
};

const verifyToken = (token) => {
    return jwt.verify(token, process.env.JWT_SECRET);
};

6.3 速率限制 #

javascript
const rateLimit = require('express-rate-limit');

const loginLimiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 5,
    message: '登录尝试过多,请稍后再试'
});

app.post('/auth/login', loginLimiter, loginHandler);

七、HTTPS配置 #

7.1 强制HTTPS #

javascript
app.use((req, res, next) => {
    if (!req.secure && req.get('x-forwarded-proto') !== 'https') {
        return res.redirect(`https://${req.get('host')}${req.url}`);
    }
    next();
});

7.2 HSTS #

javascript
app.use(helmet.hsts({
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
}));

八、完整配置 #

javascript
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const rateLimit = require('express-rate-limit');
const mongoSanitize = require('express-mongo-sanitize');
const xss = require('xss-clean');
const hpp = require('hpp');

const app = express();

app.use(helmet());

app.use(cors({
    origin: process.env.CORS_ORIGIN,
    credentials: true
}));

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000,
    max: 100
});
app.use('/api', limiter);

app.use(express.json({ limit: '10kb' }));

app.use(mongoSanitize());

app.use(xss());

app.use(hpp());

module.exports = app;

九、总结 #

安全要点:

措施 说明
Helmet 安全HTTP头
CSRF 跨站请求伪造防护
XSS 跨站脚本防护
参数化查询 SQL注入防护
密码哈希 密码安全存储
HTTPS 加密传输

下一步,让我们学习会话管理!

最后更新:2026-03-28