mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-09-17 10:56:39 +08:00
更新:文件类型检测白名单
This commit is contained in:
parent
bb68f050bf
commit
55fc58da3d
@ -57,6 +57,7 @@
|
||||
<snakeyaml.version>2.2</snakeyaml.version>
|
||||
<freemarker.version>2.3.33</freemarker.version>
|
||||
<jsoup.version>1.18.1</jsoup.version>
|
||||
<tika.version>3.1.0</tika.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -325,6 +326,12 @@
|
||||
<version>${freemarker.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<version>${tika.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
@ -273,6 +273,11 @@
|
||||
<artifactId>freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -2,10 +2,19 @@ package net.lab1024.sa.base.module.support.securityprotect.service;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import net.lab1024.sa.base.common.domain.ResponseDTO;
|
||||
import org.apache.tika.config.TikaConfig;
|
||||
import org.apache.tika.exception.TikaException;
|
||||
import org.apache.tika.io.TikaInputStream;
|
||||
import org.apache.tika.metadata.Metadata;
|
||||
import org.apache.tika.metadata.TikaCoreProperties;
|
||||
import org.apache.tika.mime.MediaType;
|
||||
import org.apache.tika.mime.MimeTypes;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 三级等保 文件上传 相关
|
||||
@ -23,6 +32,28 @@ public class SecurityFileService {
|
||||
@Resource
|
||||
private Level3ProtectConfigService level3ProtectConfigService;
|
||||
|
||||
// 定义白名单MIME类型
|
||||
private static final List<String> ALLOWED_MIME_TYPES = Arrays.asList(
|
||||
"application/json",
|
||||
"application/zip",
|
||||
"application/x-7z-compressed",
|
||||
"application/pdf",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-powerpoint",
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-works",
|
||||
"text/csv",
|
||||
"audio/*",
|
||||
"video/*",
|
||||
// 图片类型 svg有安全隐患,所以不使用"image/*"
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"image/bmp"
|
||||
);
|
||||
|
||||
/**
|
||||
* 检测文件安全类型
|
||||
@ -38,15 +69,50 @@ public class SecurityFileService {
|
||||
}
|
||||
|
||||
// 文件类型安全检测
|
||||
if (!level3ProtectConfigService.isFileDetectFlag()) {
|
||||
return ResponseDTO.ok();
|
||||
if (level3ProtectConfigService.isFileDetectFlag()) {
|
||||
String fileType = getFileMimeType(file);
|
||||
if(ALLOWED_MIME_TYPES.stream()
|
||||
.noneMatch(allowedType -> matchesMimeType(fileType, allowedType))){
|
||||
return ResponseDTO.userErrorParam("禁止上传此文件类型");
|
||||
}
|
||||
}
|
||||
|
||||
// 检测文件类型
|
||||
// .....
|
||||
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的 MIME 类型
|
||||
*
|
||||
* @param file 要检查的文件
|
||||
* @return 文件的 MIME 类型
|
||||
*
|
||||
*/
|
||||
public static String getFileMimeType(MultipartFile file) {
|
||||
try {
|
||||
TikaConfig tika = new TikaConfig();
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, file.getOriginalFilename());
|
||||
TikaInputStream stream = TikaInputStream.get(file.getInputStream());
|
||||
MediaType mimetype = tika.getDetector().detect(stream, metadata);
|
||||
return mimetype.toString();
|
||||
} catch (IOException | TikaException e) {
|
||||
return MimeTypes.OCTET_STREAM;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件的 MIME 类型是否与指定的MIME 类型匹配(支持通配符)
|
||||
*
|
||||
* @param fileType 文件的 MIME 类型
|
||||
* @param mimetype MIME 类型(支持通配符)
|
||||
* @return 是否匹配
|
||||
*/
|
||||
private static boolean matchesMimeType(String fileType, String mimetype) {
|
||||
if (mimetype.endsWith("/*")) {
|
||||
String prefix = mimetype.substring(0, mimetype.length() - 1);
|
||||
return fileType.startsWith(prefix);
|
||||
} else {
|
||||
return fileType.equalsIgnoreCase(mimetype);
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
@ -59,6 +59,7 @@
|
||||
<snakeyaml.version>2.2</snakeyaml.version>
|
||||
<freemarker.version>2.3.33</freemarker.version>
|
||||
<jsoup.version>1.18.1</jsoup.version>
|
||||
<tika.version>2.9.3</tika.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@ -370,6 +371,12 @@
|
||||
<version>${freemarker.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<version>${tika.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
@ -303,6 +303,11 @@
|
||||
<artifactId>freemarker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.tika</groupId>
|
||||
<artifactId>tika-core</artifactId>
|
||||
<version>${tika.version}</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
@ -1,11 +1,23 @@
|
||||
package net.lab1024.sa.base.module.support.securityprotect.service;
|
||||
|
||||
import net.lab1024.sa.base.common.domain.ResponseDTO;
|
||||
import org.apache.tika.config.TikaConfig;
|
||||
import org.apache.tika.detect.Detector;
|
||||
import org.apache.tika.exception.TikaException;
|
||||
import org.apache.tika.io.TikaInputStream;
|
||||
import org.apache.tika.metadata.Metadata;
|
||||
import org.apache.tika.metadata.TikaCoreProperties;
|
||||
import org.apache.tika.mime.MediaType;
|
||||
import org.apache.tika.mime.MimeTypes;
|
||||
import org.apache.tika.parser.AutoDetectParser;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 三级等保 文件上传 相关
|
||||
@ -23,6 +35,28 @@ public class SecurityFileService {
|
||||
@Resource
|
||||
private Level3ProtectConfigService level3ProtectConfigService;
|
||||
|
||||
// 定义白名单MIME类型
|
||||
private static final List<String> ALLOWED_MIME_TYPES = Arrays.asList(
|
||||
"application/json",
|
||||
"application/zip",
|
||||
"application/x-7z-compressed",
|
||||
"application/pdf",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-powerpoint",
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/vnd.ms-works",
|
||||
"text/csv",
|
||||
"audio/*",
|
||||
"video/*",
|
||||
// 图片类型 svg有安全隐患,所以不使用"image/*"
|
||||
"image/jpeg",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"image/bmp"
|
||||
);
|
||||
|
||||
/**
|
||||
* 检测文件安全类型
|
||||
@ -38,15 +72,50 @@ public class SecurityFileService {
|
||||
}
|
||||
|
||||
// 文件类型安全检测
|
||||
if (!level3ProtectConfigService.isFileDetectFlag()) {
|
||||
return ResponseDTO.ok();
|
||||
if (level3ProtectConfigService.isFileDetectFlag()) {
|
||||
String fileType = getFileMimeType(file);
|
||||
if(ALLOWED_MIME_TYPES.stream()
|
||||
.noneMatch(allowedType -> matchesMimeType(fileType, allowedType))){
|
||||
return ResponseDTO.userErrorParam("禁止上传此文件类型");
|
||||
}
|
||||
}
|
||||
|
||||
// 检测文件类型
|
||||
// .....
|
||||
|
||||
return ResponseDTO.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件的 MIME 类型
|
||||
*
|
||||
* @param file 要检查的文件
|
||||
* @return 文件的 MIME 类型
|
||||
*
|
||||
*/
|
||||
public static String getFileMimeType(MultipartFile file) {
|
||||
try {
|
||||
TikaConfig tika = new TikaConfig();
|
||||
Metadata metadata = new Metadata();
|
||||
metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, file.getOriginalFilename());
|
||||
TikaInputStream stream = TikaInputStream.get(file.getInputStream());
|
||||
MediaType mimetype = tika.getDetector().detect(stream, metadata);
|
||||
return mimetype.toString();
|
||||
} catch (IOException | TikaException e) {
|
||||
return MimeTypes.OCTET_STREAM;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查文件的 MIME 类型是否与指定的MIME 类型匹配(支持通配符)
|
||||
*
|
||||
* @param fileType 文件的 MIME 类型
|
||||
* @param mimetype MIME 类型(支持通配符)
|
||||
* @return 是否匹配
|
||||
*/
|
||||
private static boolean matchesMimeType(String fileType, String mimetype) {
|
||||
if (mimetype.endsWith("/*")) {
|
||||
String prefix = mimetype.substring(0, mimetype.length() - 1);
|
||||
return fileType.startsWith(prefix);
|
||||
} else {
|
||||
return fileType.equalsIgnoreCase(mimetype);
|
||||
}
|
||||
}
|
||||
}
|
||||
;
|
Loading…
Reference in New Issue
Block a user