MST

星途 面试题库

面试题:Node.js Express 文件上传与下载的性能优化及安全加固

在高并发场景下,如何对Node.js Express实现的文件上传与下载功能进行性能优化?例如,从流处理、缓存策略等方面阐述。同时,针对文件上传与下载过程中可能出现的安全风险,如文件类型伪造、路径遍历攻击等,说明相应的安全加固措施及原理。
29.2万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

性能优化

  1. 流处理
    • 文件上传:使用busboyexpress - 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模块,它在内存中模拟文件系统,对于小文件的上传处理,性能会有显著提升。但要注意设置合理的内存上限,避免内存溢出。

安全加固措施及原理

  1. 文件类型伪造防范
    • 原理:文件类型伪造通常是攻击者通过修改文件扩展名来绕过文件类型检查。实际文件内容与声称的文件类型不一致,可能导致安全漏洞,如执行恶意脚本等。
    • 措施
      • 使用文件头检查:不同类型的文件有特定的文件头标识。例如,PNG文件的文件头是89 50 4E 47 0D 0A 1A 0A。在Node.js中,可以使用file - type模块,它通过读取文件头来准确判断文件类型。例如:
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)) {
    // 进行文件操作
}