Security hardening and vulnerability protection
Security Hardening and Vulnerability Protection
As the most popular web framework in the Node.js ecosystem, the security of Express directly impacts the stability of the entire application. From request validation to dependency management, each aspect requires targeted protective measures.
Request Input Validation
Untreated user input is the most common source of security vulnerabilities. Express's built-in express-validator
middleware can effectively filter illegal input:
const { body, validationResult } = require('express-validator');
app.post('/user',
body('username').isLength({ min: 5 }).trim().escape(),
body('email').isEmail().normalizeEmail(),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// Secure processing logic
}
);
Special character handling requires particular attention, such as SQL injection protection:
const mysql = require('mysql2/promise');
const pool = mysql.createPool(...);
app.get('/search', async (req, res) => {
const [rows] = await pool.query(
'SELECT * FROM products WHERE name = ?',
[req.query.keyword] // Use parameterized queries
);
res.json(rows);
});
Response Header Security Configuration
Insecure HTTP headers can expose system information or lead to cross-site scripting attacks. The helmet
middleware can automatically set secure headers:
const helmet = require('helmet');
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "trusted.cdn.com"]
}
},
hsts: { maxAge: 31536000, includeSubDomains: true }
}));
Example of special configuration for APIs:
app.use((req, res, next) => {
res.removeHeader('X-Powered-By');
res.set('X-Content-Type-Options', 'nosniff');
res.set('X-Frame-Options', 'DENY');
next();
});
Session Management Security
Session identifiers require special protective measures:
const session = require('express-session');
const RedisStore = require('connect-redis')(session);
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'strict',
maxAge: 24 * 60 * 60 * 1000
}
}));
Sensitive operations require secondary verification:
app.post('/transfer', requireAuth, (req, res) => {
if (!req.session.secondFactor) {
return res.status(403).send('Secondary verification required');
}
// Fund transfer logic
});
Dependency Component Security
Third-party library vulnerabilities can become attack vectors. Use npm audit
for regular scanning:
npm audit --production
Example of automated vulnerability checking in CI configuration:
# .github/workflows/audit.yml
name: Security Audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: npm audit --audit-level=moderate
File Upload Protection
Malicious file uploads are common attack vectors:
const multer = require('multer');
const upload = multer({
limits: { fileSize: 1024 * 1024 },
fileFilter: (req, file, cb) => {
if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) {
return cb(new Error('Only image files are allowed'));
}
cb(null, true);
}
});
app.post('/upload', upload.single('avatar'), (req, res) => {
// Secure file processing
});
Rate Limiting Protection
Prevent brute-force attacks:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
message: 'Too many requests'
});
app.use('/login', limiter);
Dynamic IP blocking strategy:
const failedAttempts = new Map();
app.post('/login', (req, res, next) => {
const ip = req.ip;
const attempts = failedAttempts.get(ip) || 0;
if (attempts > 5) {
return res.status(429).send('Please try again later');
}
// Validation logic
if (!valid) {
failedAttempts.set(ip, attempts + 1);
setTimeout(() => failedAttempts.delete(ip), 3600000);
}
});
Error Handling Standards
Improper error messages can leak system details:
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({
error: 'Internal server error',
reference: generateErrorId() // Do not expose specific errors
});
});
Handling differences between production and development environments:
app.use((err, req, res, next) => {
const response = {
message: process.env.NODE_ENV === 'development'
? err.message
: 'Operation failed'
};
res.status(err.status || 500).json(response);
});
Security Logging
Complete audit logs should include:
const winston = require('winston');
const logger = winston.createLogger({
transports: [
new winston.transports.File({
filename: 'security.log',
level: 'warn',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
)
})
]
});
app.use((req, res, next) => {
logger.warn({
method: req.method,
url: req.originalUrl,
ip: req.ip,
userAgent: req.get('User-Agent')
});
next();
});
Continuous Security Practices
Automated security testing integration:
// test/security.test.js
const request = require('supertest');
const app = require('../app');
describe('Security Tests', () => {
it('Should block XSS attacks', async () => {
const res = await request(app)
.get('/search?q=<script>alert(1)</script>');
expect(res.text).not.toContain('<script>');
});
});
Example of dependency update strategy:
{
"scripts": {
"update-check": "npm outdated --json || true",
"safe-update": "npm update --save --save-exact"
}
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:错误处理与日志记录策略
下一篇:缓存策略与实现方案