You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

文件扩展名验证Windows失效Mac正常,如何修复该问题?

问题原因及解决方案

核心问题

你的代码在Windows系统验证失效主要有两个原因:

  1. 大小写不兼容:Windows文件名不区分大小写,若用户上传.EXE/.ExE这类大小写混合的文件,原代码的大小写敏感匹配会直接失效。
  2. 扩展名匹配逻辑错误:原代码中forbiddenExt数组存储的是带点的扩展名(如.exe),但计算出的fileExtension是不带点的(如exe),本质上includes永远无法匹配——你提到Mac能拦截,大概率是Mac环境下上传的文件扩展名都是小写,且实际代码里forbiddenExt是不带点的,但Windows的大小写问题依然存在。

修正后的代码

方案一:匹配带点的扩展名(推荐)

async upload(
  @UploadedFile() file: Express.Multer.File,
  @Body() body: FileUploadDto,
) {
  const forbiddenExt = ['.exe', '.bat'];
  const fileName = file.filename || file.originalname;
  
  // 正确获取带点的扩展名并统一转为小写
  const extIndex = fileName.lastIndexOf('.');
  const fileExtension = extIndex === -1 ? '' : fileName.slice(extIndex).toLowerCase();

  const hasForbiddenExtension = forbiddenExt.includes(fileExtension);

  if (hasForbiddenExtension) {
    throw new HttpException(
      'File type is not supported. Upload only .apk or .ipa',
      400,
    );
  }
  
  const response = await this.uploadFile(
    `${body.filename}`,
    file.buffer,
  );

  return {
    success: true,
  };
}

方案二:匹配不带点的扩展名

async upload(
  @UploadedFile() file: Express.Multer.File,
  @Body() body: FileUploadDto,
) {
  const forbiddenExt = ['exe', 'bat'];
  const fileName = file.filename || file.originalname;
  
  // 获取不带点的扩展名并统一转为小写
  const extIndex = fileName.lastIndexOf('.');
  const fileExtension = extIndex === -1 ? '' : fileName.slice(extIndex + 1).toLowerCase();

  const hasForbiddenExtension = forbiddenExt.includes(fileExtension);

  if (hasForbiddenExtension) {
    throw new HttpException(
      'File type is not supported. Upload only .apk or .ipa',
      400,
    );
  }
  
  const response = await this.uploadFile(
    `${body.filename}`,
    file.buffer,
  );

  return {
    success: true,
  };
}

额外优化建议

仅靠扩展名验证不安全,用户可以手动修改扩展名绕过限制,建议同时验证文件MIME类型:

async upload(
  @UploadedFile() file: Express.Multer.File,
  @Body() body: FileUploadDto,
) {
  const forbiddenExt = ['.exe', '.bat'];
  // 常见的危险文件MIME类型
  const forbiddenMimeTypes = ['application/x-msdownload', 'application/x-bat'];
  
  const fileName = file.filename || file.originalname;
  const extIndex = fileName.lastIndexOf('.');
  const fileExtension = extIndex === -1 ? '' : fileName.slice(extIndex).toLowerCase();

  // 同时验证扩展名和MIME类型
  const hasForbiddenExtension = forbiddenExt.includes(fileExtension);
  const hasForbiddenMimeType = forbiddenMimeTypes.includes(file.mimetype);

  if (hasForbiddenExtension || hasForbiddenMimeType) {
    throw new HttpException(
      'File type is not supported. Upload only .apk or .ipa',
      400,
    );
  }
  
  const response = await this.uploadFile(
    `${body.filename}`,
    file.buffer,
  );

  return {
    success: true,
  };
}

内容的提问来源于stack exchange,提问作者saravanan mp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 08:53:16