面试题答案
一键面试性能优化
- 流处理
- 文件上传:使用
busboy
或express - fileupload
等中间件时,利用流的方式处理上传文件。例如,busboy
可以通过busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {})
事件,将上传的文件以流的形式直接写入目标存储位置(如文件系统或云存储),而不是先全部加载到内存中。这样可以大大减少内存占用,提高高并发处理能力。 - 文件下载:对于文件下载,使用
fs.createReadStream
创建可读流,然后将其管道到响应流中。例如:
- 文件上传:使用
const express = require('express');
const app = express();
const fs = require('fs');
app.get('/download', (req, res) => {
const filePath = 'path/to/your/file';
const readStream = fs.createReadStream(filePath);
readStream.pipe(res);
});
通过这种方式,数据可以以流的形式从文件系统直接传输到客户端,避免一次性将整个文件加载到内存中。
2. 缓存策略
- 文件下载缓存:对于不经常变化的文件,可以使用HTTP缓存机制。在Express中,可以通过res.set('Cache - Control', 'public, max - age = 31536000')
(设置一年的缓存时间)来设置缓存控制头。这样,相同文件的后续请求可以直接从客户端缓存中获取,减轻服务器压力。
- 文件上传缓存:对于文件上传过程中的临时文件,可以考虑在内存中缓存较小的文件(在合理的内存限制内),以减少磁盘I/O操作。例如,使用memory - fs
模块,它在内存中模拟文件系统,对于小文件的上传处理,性能会有显著提升。但要注意设置合理的内存上限,避免内存溢出。
安全加固措施及原理
- 文件类型伪造防范
- 原理:文件类型伪造通常是攻击者通过修改文件扩展名来绕过文件类型检查。实际文件内容与声称的文件类型不一致,可能导致安全漏洞,如执行恶意脚本等。
- 措施:
- 使用文件头检查:不同类型的文件有特定的文件头标识。例如,PNG文件的文件头是
89 50 4E 47 0D 0A 1A 0A
。在Node.js中,可以使用file - type
模块,它通过读取文件头来准确判断文件类型。例如:
- 使用文件头检查:不同类型的文件有特定的文件头标识。例如,PNG文件的文件头是
const fileType = require('file - type');
const fs = require('fs');
const buffer = fs.readFileSync('path/to/file');
const type = fileType(buffer);
if (type && type.mime === 'image/png') {
// 处理PNG文件
}
- **白名单验证**:维护一个允许上传的文件类型白名单。例如,只允许上传`['image/png', 'image/jpeg', 'application/pdf']`等类型的文件。在验证文件类型后,与白名单进行比对,只有在白名单内的文件才允许上传。
2. 路径遍历攻击防范
- 原理:攻击者通过构造恶意的文件路径,如../../../etc/passwd
,试图访问服务器上非预期的文件或目录,获取敏感信息或执行恶意操作。
- 措施:
- 规范化路径:使用path.normalize
方法对用户提供的路径进行规范化。例如:
const path = require('path');
const userProvidedPath = '../malicious/path';
const normalizedPath = path.normalize(userProvidedPath);
// 检查规范化后的路径是否符合预期
- **绝对路径限制**:只允许使用绝对路径进行文件操作,并且限制在特定的目录范围内。例如,只允许在`/uploads`目录下进行文件上传和下载操作。可以通过判断文件路径是否以允许的目录开头来实现:
const allowedDir = '/uploads';
const filePath = '/uploads/user/file.txt';
if (filePath.startsWith(allowedDir)) {
// 进行文件操作
}