面试题答案
一键面试提升 HTTPS 服务器性能的方法
- 启用 HTTP/2:
- HTTP/2 具有多路复用、头部压缩等特性,相比 HTTP/1.1 能显著提升性能。在 Node.js 中使用
http2
模块来启用 HTTP/2 协议。例如:
const http2 = require('http2'); const server = http2.createSecureServer({ key: fs.readFileSync('path/to/key.pem'), cert: fs.readFileSync('path/to/cert.pem') }); server.on('stream', (stream, headers) => { stream.respond({ 'content-type': 'text/plain', ':status': 200 }); stream.end('Hello, World!'); }); server.listen(8443);
- HTTP/2 具有多路复用、头部压缩等特性,相比 HTTP/1.1 能显著提升性能。在 Node.js 中使用
- 优化 SSL/TLS 配置:
- 选择合适的加密套件:优先使用现代、安全且高效的加密套件。可以通过
ciphers
选项来配置,如const options = { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem'), ciphers: 'ECDHE - RSA - AES256 - GCM - SHA384:ECDHE - RSA - AES128 - GCM - SHA256' };
- 启用 TLS 会话复用:通过设置
sessionTicketKey
来启用 TLS 会话复用,减少 TLS 握手开销。例如const options = { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem'), sessionTicketKey: Buffer.from('a 32 - byte key', 'hex') };
- 选择合适的加密套件:优先使用现代、安全且高效的加密套件。可以通过
- 负载均衡:
- 硬件负载均衡器:使用专业的硬件设备(如 F5 Big - IP)来分发流量,它能处理大量并发请求并提供一定的安全防护。
- 软件负载均衡:如 Nginx 或 HAProxy。在 Node.js 环境中,可以将 Nginx 配置为反向代理服务器,将请求均衡地分发到多个 Node.js HTTPS 服务器实例上。例如 Nginx 配置如下:
upstream nodejs_servers { server 192.168.1.100:8443; server 192.168.1.101:8443; } server { listen 443 ssl; server_name your_domain.com; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; location / { proxy_pass https://nodejs_servers; proxy_set_header Host $host; proxy_set_header X - Real - IP $remote_addr; proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for; proxy_set_header X - Forwarded - Proto $scheme; } }
- 缓存:
- 静态资源缓存:对于不经常变化的静态资源(如 CSS、JavaScript、图片等),可以设置合适的缓存头。在 Node.js 中,可以使用
http - cache - response
等中间件来实现。例如:
const express = require('express'); const app = express(); const cacheResponse = require('http - cache - response'); app.get('/static/js/app.js', cacheResponse({ status: 200, headers: { 'Cache - Control':'public, max - age = 31536000' } }), (req, res) => { res.sendFile(__dirname + '/public/js/app.js'); });
- 动态内容缓存:对于动态生成但变化不频繁的内容,可以使用内存缓存(如
node - cache
)或分布式缓存(如 Redis)。例如使用node - cache
:
const NodeCache = require('node - cache'); const myCache = new NodeCache(); app.get('/dynamic - data', async (req, res) => { const cachedData = myCache.get('dynamic - data - key'); if (cachedData) { return res.json(cachedData); } const newData = await fetchDynamicData(); myCache.set('dynamic - data - key', newData); res.json(newData); });
- 静态资源缓存:对于不经常变化的静态资源(如 CSS、JavaScript、图片等),可以设置合适的缓存头。在 Node.js 中,可以使用
- 优化代码:
- 异步处理:确保所有 I/O 操作(如数据库查询、文件读取等)都是异步的,充分利用 Node.js 的事件驱动和非阻塞 I/O 特性。例如使用
async/await
处理数据库查询:
const mysql = require('mysql2/promise'); const connection = await mysql.createConnection({ host: 'localhost', user: 'root', password: 'password', database: 'test' }); const [rows] = await connection.query('SELECT * FROM users');
- 减少内存占用:避免在请求处理过程中创建大量不必要的对象,及时释放不再使用的资源。例如,在处理完文件读取后,关闭文件描述符:
const fs = require('fs'); const readableStream = fs.createReadStream('path/to/file'); readableStream.on('end', () => { readableStream.close(); });
- 异步处理:确保所有 I/O 操作(如数据库查询、文件读取等)都是异步的,充分利用 Node.js 的事件驱动和非阻塞 I/O 特性。例如使用
加固服务器安全性,防止常见网络攻击
- 防止中间人攻击:
- 证书验证:
- 确保服务器使用的 SSL/TLS 证书是由受信任的证书颁发机构(CA)颁发的。在 Node.js 中,当进行 HTTPS 请求时,默认会验证服务器证书。如果需要自定义证书验证逻辑,可以使用
https.request
的rejectUnauthorized
选项。例如:
const https = require('https'); const options = { hostname: 'example.com', port: 443, path: '/', method: 'GET', rejectUnauthorized: true }; const req = https.request(options, (res) => { // 处理响应 }); req.end();
- 定期更新证书,避免证书过期导致安全风险。
- 确保服务器使用的 SSL/TLS 证书是由受信任的证书颁发机构(CA)颁发的。在 Node.js 中,当进行 HTTPS 请求时,默认会验证服务器证书。如果需要自定义证书验证逻辑,可以使用
- 公钥固定(HPKP,HTTP Public Key Pinning):虽然 HPKP 已被弃用,但曾经它可以通过在服务器响应头中添加
Public - Key - Pin
字段,指定服务器预期的公钥哈希,浏览器会验证服务器证书的公钥哈希是否与指定的一致,从而防止中间人替换证书。在 Node.js 中,可以通过设置响应头来实现:
app.get('*', (req, res) => { res.setHeader('Public - Key - Pin','max - age = 604800; pin - sha256 = "base64 - encoded - public - key - hash";'); res.send('Hello, World!'); });
- 证书验证:
- 防止 DDoS 攻击:
- 限流:使用中间件如
express - rate - limit
来限制单个 IP 地址在一定时间内的请求次数。例如:
const rateLimit = require('express - rate - limit'); const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15分钟 max: 100, // 每个IP在15分钟内最多100个请求 message: 'Too many requests from this IP, please try again later.' }); app.use(limiter);
- 黑洞路由:与网络服务提供商合作,设置黑洞路由,将大量恶意流量重定向到一个不存在的网络地址,避免服务器受到影响。
- 限流:使用中间件如
- 防止 SQL 注入攻击:
- 参数化查询:在进行数据库操作时,使用参数化查询而不是拼接 SQL 字符串。例如在 MySQL 中使用
mysql2
模块:
const mysql = require('mysql2/promise'); const connection = await mysql.createConnection({ host: 'localhost', user: 'root', password: 'password', database: 'test' }); const username = req.body.username; const [rows] = await connection.query('SELECT * FROM users WHERE username =?', [username]);
- 参数化查询:在进行数据库操作时,使用参数化查询而不是拼接 SQL 字符串。例如在 MySQL 中使用
- 防止 XSS 攻击:
- 输入验证和过滤:对用户输入的数据进行严格的验证和过滤,只允许合法的字符和格式。例如使用
validator
模块验证邮箱地址:
const validator = require('validator'); const email = req.body.email; if (validator.isEmail(email)) { // 处理邮箱 } else { res.status(400).send('Invalid email'); }
- 输出编码:在将数据输出到页面时,对特殊字符进行编码,防止恶意脚本执行。例如在使用 EJS 模板引擎时,会自动对输出内容进行 HTML 转义:
<p><%= userInput %></p>
- 输入验证和过滤:对用户输入的数据进行严格的验证和过滤,只允许合法的字符和格式。例如使用
- 防止 CSRF 攻击:
- 生成和验证 CSRF 令牌:在用户登录后,为每个用户会话生成一个唯一的 CSRF 令牌,并在表单提交或 AJAX 请求时进行验证。例如在 Express 中使用
csurf
中间件:
const csrf = require('csurf'); const csrfProtection = csrf({ cookie: true }); app.get('/form', csrfProtection, (req, res) => { res.render('form', { csrfToken: req.csrfToken() }); }); app.post('/submit - form', csrfProtection, (req, res) => { // 处理表单提交 });
- 生成和验证 CSRF 令牌:在用户登录后,为每个用户会话生成一个唯一的 CSRF 令牌,并在表单提交或 AJAX 请求时进行验证。例如在 Express 中使用